mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
NAVY
This commit is contained in:
parent
04923b65b2
commit
2f6d9b640f
@ -2,13 +2,16 @@
|
|||||||
--
|
--
|
||||||
-- **Main Features:**
|
-- **Main Features:**
|
||||||
--
|
--
|
||||||
-- * Stuff
|
-- * Find path from A to B.
|
||||||
|
-- * Pre-defined as well as custom valid neighbour functions.
|
||||||
|
-- * Pre-defined as well as custom cost functions.
|
||||||
|
-- * Easy rectangular grid setup.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
-- @module Core.Astar
|
-- @module Core.Astar
|
||||||
-- @image CORE_Atar.png
|
-- @image CORE_Astar.png
|
||||||
|
|
||||||
|
|
||||||
--- ASTAR class.
|
--- ASTAR class.
|
||||||
@ -21,20 +24,110 @@
|
|||||||
-- @field #ASTAR.Node endNode End node.
|
-- @field #ASTAR.Node endNode End node.
|
||||||
-- @field Core.Point#COORDINATE startCoord Start coordinate.
|
-- @field Core.Point#COORDINATE startCoord Start coordinate.
|
||||||
-- @field Core.Point#COORDINATE endCoord End coordinate.
|
-- @field Core.Point#COORDINATE endCoord End coordinate.
|
||||||
-- @field #func ValidNeighbourFunc Function to check if a node is valid.
|
-- @field #function ValidNeighbourFunc Function to check if a node is valid.
|
||||||
-- @field #table ValidNeighbourArg Optional arguments passed to the valid neighbour function.
|
-- @field #table ValidNeighbourArg Optional arguments passed to the valid neighbour function.
|
||||||
|
-- @field #function CostFunc Function to calculate the heuristic "cost" to go from one node to another.
|
||||||
|
-- @field #table CostArg Optional arguments passed to the cost function.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- When nothing goes right... Go left!
|
--- When nothing goes right... Go left!
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- # The ASTAR Concept
|
-- # The ASTAR Concept
|
||||||
--
|
--
|
||||||
-- Pathfinding algorithm.
|
-- Pathfinding algorithm.
|
||||||
--
|
--
|
||||||
|
--
|
||||||
|
-- # Start and Goal
|
||||||
|
--
|
||||||
|
-- The first thing we need to define is obviously the place where we want to start and where we want to go eventually.
|
||||||
|
--
|
||||||
|
-- ## Start
|
||||||
|
--
|
||||||
|
-- The start
|
||||||
|
--
|
||||||
|
-- ## Goal
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Nodes
|
||||||
|
--
|
||||||
|
-- ## Rectangular Grid
|
||||||
|
--
|
||||||
|
-- A rectangular grid can be created using the @{#ASTAR.CreateGrid}(*ValidSurfaceTypes, BoxHY, SpaceX, deltaX, deltaY, MarkGrid*), where
|
||||||
|
--
|
||||||
|
-- * *ValidSurfaceTypes* is a table of valid surface types. By default all surface types are valid.
|
||||||
|
-- * *BoxXY* is the width of the grid perpendicular the the line between start and end node. Default is 40,000 meters (40 km).
|
||||||
|
-- * *SpaceX* is the additional space behind the start and end nodes. Default is 20,000 meters (20 km).
|
||||||
|
-- * *deltaX* is the grid spacing between nodes in the direction of start and end node. Default is 2,000 meters (2 km).
|
||||||
|
-- * *deltaY* is the grid spacing perpendicular to the direction of start and end node. Default is the same as *deltaX*.
|
||||||
|
-- * *MarkGrid* If set to *true*, this places marker on the F10 map on each grid node. Note that this can stall DCS if too many nodes are created.
|
||||||
|
--
|
||||||
|
-- ## Valid Surfaces
|
||||||
|
--
|
||||||
|
-- Certain unit types can only travel on certain surfaces types, for example
|
||||||
|
--
|
||||||
|
-- * Naval units can only travel on water (that also excludes shallow water in DCS currently),
|
||||||
|
-- * Ground units can only traval on land.
|
||||||
|
--
|
||||||
|
-- By restricting the surface type in the grid construction, we also reduce the number of nodes, which makes the algorithm more efficient.
|
||||||
|
--
|
||||||
|
-- ## Box Width (BoxHY)
|
||||||
|
--
|
||||||
|
-- The box width needs to be large enough to capture all paths you want to consider.
|
||||||
|
--
|
||||||
|
-- ## Space in X
|
||||||
|
--
|
||||||
|
-- The space in X value is important if the algorithm needs to to backwards from the start node or needs to extend even further than the end node.
|
||||||
|
--
|
||||||
|
-- ## Grid Spacing
|
||||||
|
--
|
||||||
|
-- The grid spacing is an important factor as it determines the number of nodes and hence the performance of the algorithm. It should be as large as possible.
|
||||||
|
-- However, if the value is too large, the algorithm might fail to get a valid path.
|
||||||
|
--
|
||||||
|
-- A good estimate of the grid spacing is to set it to be smaller (~ half the size) of the smallest gap you need to path.
|
||||||
|
--
|
||||||
|
-- # Valid Neighbours
|
||||||
|
--
|
||||||
|
-- The A* algorithm needs to know if a transition from one node to another is allowed or not. By default, hopping from one node to another is always possible.
|
||||||
|
--
|
||||||
|
-- ## Line of Sight
|
||||||
|
--
|
||||||
|
-- For naval
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Heuristic Cost
|
||||||
|
--
|
||||||
|
-- In order to determine the optimal path, the pathfinding algorithm needs to know, how costly it is to go from one node to another.
|
||||||
|
-- Often, this can simply be determined by the distance between two nodes. Therefore, the default cost function is set to be the 2D distance between two nodes.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Calculate the Path
|
||||||
|
--
|
||||||
|
-- Finally, we have to calculate the path. This is done by the @{ASTAR.GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||||
|
-- describe the optimal path from the start node to the end node.
|
||||||
|
--
|
||||||
|
-- By default, the start and end node are include in the table that is returned.
|
||||||
|
--
|
||||||
|
-- Note that a valid path must not always exist. So you should check if the function returns *nil*.
|
||||||
|
--
|
||||||
|
-- Common reasons that a path cannot be found are:
|
||||||
|
--
|
||||||
|
-- * The grid is too small ==> increase grid size, e.g. *BoxHY* and/or *SpaceX* if you use a rectangular grid.
|
||||||
|
-- * The grid spacing is too large ==> decrease *deltaX* and/or *deltaY*
|
||||||
|
-- * There simply is no valid path ==> you are screwed :(
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Examples
|
||||||
|
--
|
||||||
|
-- ## Strait of Hormuz
|
||||||
|
--
|
||||||
|
-- Carrier Group finds its way through the Stait of Hormuz.
|
||||||
|
--
|
||||||
|
-- ##
|
||||||
|
--
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- @field #ASTAR
|
-- @field #ASTAR
|
||||||
@ -45,13 +138,13 @@ ASTAR = {
|
|||||||
nodes = {},
|
nodes = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Defence condition.
|
--- Node data.
|
||||||
-- @type ASTAR.Node
|
-- @type ASTAR.Node
|
||||||
-- @field Core.Point#COORDINATE coordinate Coordinate of the node.
|
-- @field Core.Point#COORDINATE coordinate Coordinate of the node.
|
||||||
-- @field #number surfacetype Surface type.
|
-- @field #number surfacetype Surface type.
|
||||||
|
|
||||||
--- ASTAR infinity
|
--- ASTAR infinity.
|
||||||
-- @field #string INF
|
-- @field #number INF
|
||||||
ASTAR.INF=1/0
|
ASTAR.INF=1/0
|
||||||
|
|
||||||
--- ASTAR class version.
|
--- ASTAR class version.
|
||||||
@ -137,14 +230,14 @@ end
|
|||||||
--- Add a node to the table of grid nodes specifying its coordinate.
|
--- Add a node to the table of grid nodes specifying its coordinate.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where the node is created.
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where the node is created.
|
||||||
-- @return #ASTAR self
|
-- @return #ASTAR.Node The node.
|
||||||
function ASTAR:AddNodeFromCoordinate(Coordinate)
|
function ASTAR:AddNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
local node=self:GetNodeFromCoordinate(Coordinate)
|
local node=self:GetNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
self:AddNode(node)
|
self:AddNode(node)
|
||||||
|
|
||||||
return self
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the coordinate of a node has is at a valid surface type.
|
--- Check if the coordinate of a node has is at a valid surface type.
|
||||||
@ -214,8 +307,44 @@ function ASTAR:SetValidNeighbourDistance(MaxDistance)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the function which calculates the "cost" to go from one to another node.
|
||||||
|
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
|
||||||
|
-- Very often the distance between nodes is a good measure for the cost.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #function CostFunction Function that returns the "cost".
|
||||||
|
-- @param ... Condition function arguments if any.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostFunction(CostFunction, ...)
|
||||||
|
|
||||||
|
self.CostFunc=CostFunction
|
||||||
|
|
||||||
|
self.CostArg={}
|
||||||
|
if arg then
|
||||||
|
self.CostArg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 2D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist2D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist2D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 3D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist3D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist3D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Grid functions
|
-- Grid functions
|
||||||
@ -369,6 +498,26 @@ function ASTAR.DistMax(nodeA, nodeB, distmax)
|
|||||||
return dist<=distmax
|
return dist<=distmax
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Heuristic cost functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 2D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist2D(nodeA, nodeB)
|
||||||
|
return nodeA.coordinate:Get2DDistance(nodeB)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 3D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist3D(nodeA, nodeB)
|
||||||
|
return nodeA.coordinate:Get3DDistance(nodeB.coordinate)
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Misc functions
|
-- Misc functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -458,7 +607,7 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
local g_score, f_score = {}, {}
|
local g_score, f_score = {}, {}
|
||||||
|
|
||||||
g_score[start]=0
|
g_score[start]=0
|
||||||
f_score[start]=g_score[start]+self:HeuristicCost(start, goal)
|
f_score[start]=g_score[start]+self:_HeuristicCost(start, goal)
|
||||||
|
|
||||||
-- Set start time.
|
-- Set start time.
|
||||||
local T0=timer.getAbsTime()
|
local T0=timer.getAbsTime()
|
||||||
@ -470,12 +619,12 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
|
|
||||||
while #openset > 0 do
|
while #openset > 0 do
|
||||||
|
|
||||||
local current=self:LowestFscore(openset, f_score)
|
local current=self:_LowestFscore(openset, f_score)
|
||||||
|
|
||||||
-- Check if we are at the end node.
|
-- Check if we are at the end node.
|
||||||
if current==goal then
|
if current==goal then
|
||||||
|
|
||||||
local path=self:UnwindPath({}, came_from, goal)
|
local path=self:_UnwindPath({}, came_from, goal)
|
||||||
|
|
||||||
if not ExcludeEndNode then
|
if not ExcludeEndNode then
|
||||||
table.insert(path, goal)
|
table.insert(path, goal)
|
||||||
@ -493,26 +642,26 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
self:RemoveNode(openset, current)
|
self:_RemoveNode(openset, current)
|
||||||
table.insert(closedset, current)
|
table.insert(closedset, current)
|
||||||
|
|
||||||
local neighbors=self:NeighbourNodes(current, nodes)
|
local neighbors=self:_NeighbourNodes(current, nodes)
|
||||||
|
|
||||||
-- Loop over neighbours.
|
-- Loop over neighbours.
|
||||||
for _,neighbor in ipairs(neighbors) do
|
for _,neighbor in ipairs(neighbors) do
|
||||||
|
|
||||||
if self:NotIn(closedset, neighbor) then
|
if self:_NotIn(closedset, neighbor) then
|
||||||
|
|
||||||
local tentative_g_score=g_score[current]+self:DistNodes(current, neighbor)
|
local tentative_g_score=g_score[current]+self:_DistNodes(current, neighbor)
|
||||||
|
|
||||||
if self:NotIn(openset, neighbor) or tentative_g_score < g_score[neighbor] then
|
if self:_NotIn(openset, neighbor) or tentative_g_score < g_score[neighbor] then
|
||||||
|
|
||||||
came_from[neighbor]=current
|
came_from[neighbor]=current
|
||||||
|
|
||||||
g_score[neighbor]=tentative_g_score
|
g_score[neighbor]=tentative_g_score
|
||||||
f_score[neighbor]=g_score[neighbor]+self:HeuristicCost(neighbor, goal)
|
f_score[neighbor]=g_score[neighbor]+self:_HeuristicCost(neighbor, goal)
|
||||||
|
|
||||||
if self:NotIn(openset, neighbor) then
|
if self:_NotIn(openset, neighbor) then
|
||||||
table.insert(openset, neighbor)
|
table.insert(openset, neighbor)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -533,22 +682,18 @@ end
|
|||||||
-- A* pathfinding helper functions
|
-- A* pathfinding helper functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Calculate 2D distance between two nodes.
|
--- Heuristic "cost" function to go from node A to node B. Default is the distance between the nodes.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param #ASTAR.Node nodeA Node A.
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
-- @param #ASTAR.Node nodeB Node B.
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
-- @return #number Distance between nodes in meters.
|
-- @return #number "Cost" to go from node A to node B.
|
||||||
function ASTAR:DistNodes(nodeA, nodeB)
|
function ASTAR:_HeuristicCost(nodeA, nodeB)
|
||||||
return nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Heuristic cost function to go from node A to node B. That is simply the distance here.
|
if self.CostFunc then
|
||||||
-- @param #ASTAR self
|
return self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
||||||
-- @param #ASTAR.Node nodeA Node A.
|
else
|
||||||
-- @param #ASTAR.Node nodeB Node B.
|
return self:_DistNodes(nodeA, nodeB)
|
||||||
-- @return #number Distance between nodes in meters.
|
end
|
||||||
function ASTAR:HeuristicCost(nodeA, nodeB)
|
|
||||||
return self:DistNodes(nodeA, nodeB)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if going from a node to a neighbour is possible.
|
--- Check if going from a node to a neighbour is possible.
|
||||||
@ -556,7 +701,7 @@ end
|
|||||||
-- @param #ASTAR.Node node A node.
|
-- @param #ASTAR.Node node A node.
|
||||||
-- @param #ASTAR.Node neighbor Neighbour node.
|
-- @param #ASTAR.Node neighbor Neighbour node.
|
||||||
-- @return #boolean If true, transition between nodes is possible.
|
-- @return #boolean If true, transition between nodes is possible.
|
||||||
function ASTAR:IsValidNeighbour(node, neighbor)
|
function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||||
|
|
||||||
if self.ValidNeighbourFunc then
|
if self.ValidNeighbourFunc then
|
||||||
|
|
||||||
@ -568,9 +713,21 @@ function ASTAR:IsValidNeighbour(node, neighbor)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function
|
--- Calculate 2D distance between two nodes.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
function ASTAR:LowestFscore(set, f_score)
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
|
-- @return #number Distance between nodes in meters.
|
||||||
|
function ASTAR:_DistNodes(nodeA, nodeB)
|
||||||
|
return nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function that calculates the lowest F score.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table set The set of nodes.
|
||||||
|
-- @param #number f_score F score.
|
||||||
|
-- @return #ASTAR.Node Best node.
|
||||||
|
function ASTAR:_LowestFscore(set, f_score)
|
||||||
|
|
||||||
local lowest, bestNode = ASTAR.INF, nil
|
local lowest, bestNode = ASTAR.INF, nil
|
||||||
|
|
||||||
@ -591,14 +748,14 @@ end
|
|||||||
-- @param #ASTAR.Node theNode The node.
|
-- @param #ASTAR.Node theNode The node.
|
||||||
-- @param #table nodes Possible neighbours.
|
-- @param #table nodes Possible neighbours.
|
||||||
-- @param #table Valid neighbour nodes.
|
-- @param #table Valid neighbour nodes.
|
||||||
function ASTAR:NeighbourNodes(theNode, nodes)
|
function ASTAR:_NeighbourNodes(theNode, nodes)
|
||||||
|
|
||||||
local neighbors = {}
|
local neighbors = {}
|
||||||
for _, node in ipairs ( nodes ) do
|
for _, node in ipairs ( nodes ) do
|
||||||
|
|
||||||
if theNode~=node then
|
if theNode~=node then
|
||||||
|
|
||||||
local isvalid=self:IsValidNeighbour(theNode, node)
|
local isvalid=self:_IsValidNeighbour(theNode, node)
|
||||||
|
|
||||||
if isvalid then
|
if isvalid then
|
||||||
table.insert(neighbors, node)
|
table.insert(neighbors, node)
|
||||||
@ -616,7 +773,7 @@ end
|
|||||||
-- @param #table set Set of nodes.
|
-- @param #table set Set of nodes.
|
||||||
-- @param #ASTAR.Node theNode The node to check.
|
-- @param #ASTAR.Node theNode The node to check.
|
||||||
-- @return #boolean If true, the node is not in the set.
|
-- @return #boolean If true, the node is not in the set.
|
||||||
function ASTAR:NotIn(set, theNode)
|
function ASTAR:_NotIn(set, theNode)
|
||||||
|
|
||||||
for _, node in ipairs ( set ) do
|
for _, node in ipairs ( set ) do
|
||||||
if node == theNode then
|
if node == theNode then
|
||||||
@ -631,7 +788,7 @@ end
|
|||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param #table set Set of nodes.
|
-- @param #table set Set of nodes.
|
||||||
-- @param #ASTAR.Node theNode The node to check.
|
-- @param #ASTAR.Node theNode The node to check.
|
||||||
function ASTAR:RemoveNode(set, theNode)
|
function ASTAR:_RemoveNode(set, theNode)
|
||||||
|
|
||||||
for i, node in ipairs ( set ) do
|
for i, node in ipairs ( set ) do
|
||||||
if node == theNode then
|
if node == theNode then
|
||||||
@ -649,11 +806,11 @@ end
|
|||||||
-- @param #table map Map.
|
-- @param #table map Map.
|
||||||
-- @param #ASTAR.Node current_node The current node.
|
-- @param #ASTAR.Node current_node The current node.
|
||||||
-- @return #table Unwinded path.
|
-- @return #table Unwinded path.
|
||||||
function ASTAR:UnwindPath( flat_path, map, current_node )
|
function ASTAR:_UnwindPath( flat_path, map, current_node )
|
||||||
|
|
||||||
if map [ current_node ] then
|
if map [ current_node ] then
|
||||||
table.insert ( flat_path, 1, map [ current_node ] )
|
table.insert ( flat_path, 1, map [ current_node ] )
|
||||||
return self:UnwindPath ( flat_path, map, map [ current_node ] )
|
return self:_UnwindPath ( flat_path, map, map [ current_node ] )
|
||||||
else
|
else
|
||||||
return flat_path
|
return flat_path
|
||||||
end
|
end
|
||||||
|
|||||||
@ -175,10 +175,6 @@ do -- COORDINATE
|
|||||||
-- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate
|
-- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate
|
||||||
-- the most optimal path following the road between two coordinates.
|
-- the most optimal path following the road between two coordinates.
|
||||||
--
|
--
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- ## 8) Metric or imperial system
|
-- ## 8) Metric or imperial system
|
||||||
--
|
--
|
||||||
-- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
|
-- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
|
||||||
@ -204,23 +200,23 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- @field COORDINATE.WaypointAction
|
--- @field COORDINATE.WaypointAction
|
||||||
COORDINATE.WaypointAction = {
|
COORDINATE.WaypointAction = {
|
||||||
TurningPoint = "Turning Point",
|
TurningPoint = "Turning Point",
|
||||||
FlyoverPoint = "Fly Over Point",
|
FlyoverPoint = "Fly Over Point",
|
||||||
FromParkingArea = "From Parking Area",
|
FromParkingArea = "From Parking Area",
|
||||||
FromParkingAreaHot = "From Parking Area Hot",
|
FromParkingAreaHot = "From Parking Area Hot",
|
||||||
FromRunway = "From Runway",
|
FromRunway = "From Runway",
|
||||||
Landing = "Landing",
|
Landing = "Landing",
|
||||||
LandingReFuAr = "LandingReFuAr",
|
LandingReFuAr = "LandingReFuAr",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- @field COORDINATE.WaypointType
|
--- @field COORDINATE.WaypointType
|
||||||
COORDINATE.WaypointType = {
|
COORDINATE.WaypointType = {
|
||||||
TakeOffParking = "TakeOffParking",
|
TakeOffParking = "TakeOffParking",
|
||||||
TakeOffParkingHot = "TakeOffParkingHot",
|
TakeOffParkingHot = "TakeOffParkingHot",
|
||||||
TakeOff = "TakeOffParkingHot",
|
TakeOff = "TakeOffParkingHot",
|
||||||
TurningPoint = "Turning Point",
|
TurningPoint = "Turning Point",
|
||||||
Land = "Land",
|
Land = "Land",
|
||||||
LandingReFuAr = "LandingReFuAr",
|
LandingReFuAr = "LandingReFuAr",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1290,8 +1286,10 @@ do -- COORDINATE
|
|||||||
RoutePoint.x = self.x
|
RoutePoint.x = self.x
|
||||||
RoutePoint.y = self.z
|
RoutePoint.y = self.z
|
||||||
|
|
||||||
RoutePoint.alt = self:GetLandHeight()+1 -- self.y
|
RoutePoint.alt = self:GetLandHeight()+1
|
||||||
RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO
|
RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO
|
||||||
|
|
||||||
|
RoutePoint.type = "Turning Point"
|
||||||
|
|
||||||
RoutePoint.action = Formation or "Off Road"
|
RoutePoint.action = Formation or "Off Road"
|
||||||
RoutePoint.formation_template=""
|
RoutePoint.formation_template=""
|
||||||
@ -1921,7 +1919,7 @@ do -- COORDINATE
|
|||||||
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE ToCoordinate
|
-- @param #COORDINATE ToCoordinate
|
||||||
-- @param #number OFfset Height offset in meters. Default 2 m.
|
-- @param #number Offset Height offset in meters. Default 2 m.
|
||||||
-- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false.
|
-- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false.
|
||||||
function COORDINATE:IsLOS( ToCoordinate, Offset )
|
function COORDINATE:IsLOS( ToCoordinate, Offset )
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
-- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached.
|
-- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached.
|
||||||
-- @extends Ops.OpsGroup#OPSGROUP
|
-- @extends Ops.OpsGroup#OPSGROUP
|
||||||
|
|
||||||
--- *Something must be left to chance; nothing is sure in a sea fight above all.* -- Horatio Nelson
|
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -64,8 +64,9 @@ function ARMYGROUP:New(GroupName)
|
|||||||
|
|
||||||
-- Defaults
|
-- Defaults
|
||||||
self:SetDefaultROE()
|
self:SetDefaultROE()
|
||||||
|
self:SetDefaultAlarmstate()
|
||||||
self:SetDetection()
|
self:SetDetection()
|
||||||
self:SetPatrolAdInfinitum(true)
|
self:SetPatrolAdInfinitum(false)
|
||||||
|
|
||||||
-- Add FSM transitions.
|
-- Add FSM transitions.
|
||||||
-- From State --> Event --> To State
|
-- From State --> Event --> To State
|
||||||
@ -134,7 +135,7 @@ function ARMYGROUP:SetPatrolAdInfinitum(switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Group patrols ad inifintum. If the last waypoint is reached, it will go to waypoint one and repeat its route.
|
--- Set default cruise speed. This is the speed a group will take by default if no speed is specified explicitly.
|
||||||
-- @param #ARMYGROUP self
|
-- @param #ARMYGROUP self
|
||||||
-- @param #number Speed Speed in knots. Default 70% of max speed.
|
-- @param #number Speed Speed in knots. Default 70% of max speed.
|
||||||
-- @return #ARMYGROUP self
|
-- @return #ARMYGROUP self
|
||||||
@ -225,8 +226,8 @@ function ARMYGROUP:onafterStatus(From, Event, To)
|
|||||||
local nMissions=self:CountRemainingMissison()
|
local nMissions=self:CountRemainingMissison()
|
||||||
|
|
||||||
-- Info text.
|
-- Info text.
|
||||||
local text=string.format("State %s: Wp=%d/%d Speed=%.1f Heading=%03d Tasks=%d Missions=%d",
|
local text=string.format("State %s: Wp=%d/%d-->%d Speed=%.1f (%d) Heading=%03d ROE=%d Alarm=%d Formation=%s Tasks=%d Missions=%d",
|
||||||
fsmstate, self.currentwp, #self.waypoints, speed, hdg, nTaskTot, nMissions)
|
fsmstate, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), speed, UTILS.MpsToKnots(self.speed), hdg, self.roe, self.alarmstate, self.formation, nTaskTot, nMissions)
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -338,9 +339,12 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
|||||||
|
|
||||||
if self.ai then
|
if self.ai then
|
||||||
|
|
||||||
-- Set default ROE and ROT options.
|
-- Set default ROE option.
|
||||||
self:SetOptionROE(self.roe)
|
self:SetOptionROE(self.roe)
|
||||||
|
|
||||||
|
-- Set default Alarm State option.
|
||||||
|
self:SetOptionAlarmstate(self.alarmstate)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update route.
|
-- Update route.
|
||||||
@ -355,38 +359,33 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number n Waypoint number. Default is next waypoint.
|
-- @param #number n Waypoint number. Default is next waypoint.
|
||||||
-- @param #number Speed Speed in knots. Default cruise speed.
|
-- @param #number Speed Speed in knots. Default cruise speed.
|
||||||
-- @param #number Depth Depth in meters. Default 0 meters.
|
-- @param #number Formation Formation of the group.
|
||||||
function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
|
||||||
|
|
||||||
-- Update route from this waypoint number onwards.
|
-- Update route from this waypoint number onwards.
|
||||||
n=n or self:GetWaypointIndexNext(self.adinfinitum)
|
n=n or self:GetWaypointIndexNext(self.adinfinitum)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("FF Update route n=%d", n))
|
self:I(self.lid..string.format("FF Update route n=%d", n))
|
||||||
|
|
||||||
-- Update waypoint tasks, i.e. inject WP tasks into waypoint table.
|
-- Update waypoint tasks, i.e. inject WP tasks into waypoint table.
|
||||||
self:_UpdateWaypointTasks(n)
|
self:_UpdateWaypointTasks(n)
|
||||||
|
|
||||||
-- Waypoints.
|
-- Waypoints.
|
||||||
local waypoints={}
|
local waypoints={}
|
||||||
|
|
||||||
-- Depth for submarines.
|
|
||||||
local depth=Depth or 0
|
|
||||||
|
|
||||||
-- Get current speed in km/h.
|
|
||||||
local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH()
|
|
||||||
|
|
||||||
-- Current waypoint.
|
|
||||||
local current=self:GetCoordinate():WaypointNaval(speed, depth)
|
|
||||||
table.insert(waypoints, current)
|
|
||||||
|
|
||||||
-- Add remaining waypoints to route.
|
-- Add remaining waypoints to route.
|
||||||
for i=n, #self.waypoints do
|
for i=n, #self.waypoints do
|
||||||
local wp=self.waypoints[i]
|
|
||||||
|
-- Copy waypoint.
|
||||||
|
local wp=UTILS.DeepCopy(self.waypoints[i]) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||||
|
|
||||||
-- Set speed.
|
|
||||||
if i==n then
|
if i==n then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Next Waypoint
|
||||||
|
---
|
||||||
|
|
||||||
if Speed then
|
if Speed then
|
||||||
wp.speed=UTILS.KnotsToMps(Speed)
|
wp.speed=UTILS.KnotsToMps(Speed)
|
||||||
elseif self.speedCruise then
|
elseif self.speedCruise then
|
||||||
@ -394,8 +393,22 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
else
|
else
|
||||||
-- Take default waypoint speed.
|
-- Take default waypoint speed.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Formation then
|
||||||
|
wp.action=Formation
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Current set formation.
|
||||||
|
self.formation=wp.action
|
||||||
|
|
||||||
|
-- Current set speed in m/s.
|
||||||
|
self.speed=wp.speed
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Later Waypoint(s)
|
||||||
|
---
|
||||||
|
|
||||||
if self.speedCruise then
|
if self.speedCruise then
|
||||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
||||||
@ -405,17 +418,23 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set depth.
|
-- Debug info.
|
||||||
wp.alt=-depth --Depth and -Depth or wp.alt
|
self:I(string.format("WP %d %s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.type, wp.speed, wp.alt, wp.action))
|
||||||
|
|
||||||
-- Add waypoint.
|
-- Add waypoint.
|
||||||
table.insert(waypoints, wp)
|
table.insert(waypoints, wp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Current waypoint.
|
||||||
|
local current=self:GetCoordinate():WaypointGround(UTILS.MpsToKmph(self.speed), self.formation)
|
||||||
|
table.insert(waypoints, 1, current)
|
||||||
|
table.insert(waypoints, 1, current) -- Seems to be better to add this twice. Otherwise, the passing waypoint functions is triggered to early!
|
||||||
|
|
||||||
|
if #waypoints>2 then
|
||||||
|
|
||||||
if #waypoints>1 then
|
self:I(self.lid..string.format("Updateing route: WP %d-->%d-->%d (#%d), Speed=%.1f knots, Formation=%s",
|
||||||
|
self.currentwp, n, #self.waypoints, #waypoints-2, UTILS.MpsToKnots(self.speed), tostring(self.formation)))
|
||||||
self:I(self.lid..string.format("Updateing route: WP=%d, Speed=%.1f knots, depth=%d meters", #self.waypoints-n+1, UTILS.KmphToKnots(speed), depth))
|
|
||||||
|
|
||||||
-- Route group to all defined waypoints remaining.
|
-- Route group to all defined waypoints remaining.
|
||||||
self:Route(waypoints)
|
self:Route(waypoints)
|
||||||
@ -428,11 +447,6 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
|
|
||||||
self:I(self.lid..string.format("No waypoints left"))
|
self:I(self.lid..string.format("No waypoints left"))
|
||||||
|
|
||||||
if #self.waypoints>1 then
|
|
||||||
self:I(self.lid..string.format("Resuming route at first waypoint"))
|
|
||||||
self:__UpdateRoute(-1, 1, nil, self.depth)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -444,27 +458,24 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where to go.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate where to go.
|
||||||
-- @param #number Speed Speed in knots. Default cruise speed.
|
-- @param #number Speed Speed in knots. Default cruise speed.
|
||||||
-- @param #number Depth Depth in meters. Default 0 meters.
|
-- @param #number Formation Formation the group will use.
|
||||||
-- @param #number ResumeRoute If true, resume route after detour point was reached.
|
-- @param #number ResumeRoute If true, resume route after detour point was reached.
|
||||||
function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Depth, ResumeRoute)
|
function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation, ResumeRoute)
|
||||||
|
|
||||||
-- Waypoints.
|
-- Waypoints.
|
||||||
local waypoints={}
|
local waypoints={}
|
||||||
|
|
||||||
-- Depth for submarines.
|
|
||||||
local depth=Depth or 0
|
|
||||||
|
|
||||||
-- Get current speed in km/h.
|
-- Get current speed in km/h.
|
||||||
local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH()
|
local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH()
|
||||||
|
|
||||||
-- Current waypoint.
|
-- Current waypoint.
|
||||||
local current=self:GetCoordinate():WaypointGround(Speed, Formation, DCSTasks)
|
local current=self:GetCoordinate():WaypointGround(Speed, Formation)
|
||||||
table.insert(waypoints, current)
|
table.insert(waypoints, current)
|
||||||
|
|
||||||
-- At each waypoint report passing.
|
-- At each waypoint report passing.
|
||||||
local Task=self.group:TaskFunction("ARMYGROUP._DetourReached", self, ResumeRoute)
|
local Task=self.group:TaskFunction("ARMYGROUP._DetourReached", self, ResumeRoute)
|
||||||
|
|
||||||
local detour=Coordinate:WaypointNaval(speed, depth, {Task})
|
local detour=Coordinate:WaypointGround(Speed, Formation, {Task})
|
||||||
table.insert(waypoints, detour)
|
table.insert(waypoints, detour)
|
||||||
|
|
||||||
self:Route(waypoints)
|
self:Route(waypoints)
|
||||||
@ -482,21 +493,21 @@ end
|
|||||||
|
|
||||||
--- Function called when a group is passing a waypoint.
|
--- Function called when a group is passing a waypoint.
|
||||||
--@param Wrapper.Group#GROUP group Group that passed the waypoint
|
--@param Wrapper.Group#GROUP group Group that passed the waypoint
|
||||||
--@param #ARMYGROUP navygroup Navy group object.
|
--@param #ARMYGROUP armygroup Army group object.
|
||||||
--@param #boolean resume Resume route.
|
--@param #boolean resume Resume route.
|
||||||
function ARMYGROUP._DetourReached(group, navygroup, resume)
|
function ARMYGROUP._DetourReached(group, armygroup, resume)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
local text=string.format("Group reached detour coordinate")
|
local text=string.format("Group reached detour coordinate")
|
||||||
navygroup:I(navygroup.lid..text)
|
armygroup:I(armygroup.lid..text)
|
||||||
|
|
||||||
if resume then
|
if resume then
|
||||||
local indx=navygroup:GetWaypointIndexNext(true)
|
local indx=armygroup:GetWaypointIndexNext(true)
|
||||||
local speed=navygroup:GetSpeedToWaypoint(indx)
|
local speed=armygroup:GetSpeedToWaypoint(indx)
|
||||||
navygroup:UpdateRoute(indx, speed, navygroup.depth)
|
armygroup:__UpdateRoute(-1, indx, speed, armygroup.formation)
|
||||||
end
|
end
|
||||||
|
|
||||||
navygroup:DetourReached()
|
armygroup:DetourReached()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -511,7 +522,7 @@ function ARMYGROUP:onafterFullStop(From, Event, To)
|
|||||||
local pos=self:GetCoordinate()
|
local pos=self:GetCoordinate()
|
||||||
|
|
||||||
-- Create a new waypoint.
|
-- Create a new waypoint.
|
||||||
local wp=pos:WaypointNaval(0)
|
local wp=pos:WaypointGround(0)
|
||||||
|
|
||||||
-- Create new route consisting of only this position ==> Stop!
|
-- Create new route consisting of only this position ==> Stop!
|
||||||
self:Route({wp})
|
self:Route({wp})
|
||||||
@ -524,9 +535,10 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number Speed Speed in knots.
|
-- @param #number Speed Speed in knots.
|
||||||
function ARMYGROUP:onafterCruise(From, Event, To, Speed)
|
-- @param #number Formation Formation.
|
||||||
|
function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
|
||||||
|
|
||||||
self:UpdateRoute(nil, Speed, self.depth)
|
self:__UpdateRoute(-1, nil, Speed, Formation)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -675,9 +687,10 @@ end
|
|||||||
-- @param Core.Point#COORDINATE coordinate The coordinate of the waypoint. Use COORDINATE:SetAltitude(altitude) to define the altitude.
|
-- @param Core.Point#COORDINATE coordinate The coordinate of the waypoint. Use COORDINATE:SetAltitude(altitude) to define the altitude.
|
||||||
-- @param #number speed Speed in knots. Default is default cruise speed or 70% of max speed.
|
-- @param #number speed Speed in knots. Default is default cruise speed or 70% of max speed.
|
||||||
-- @param #number wpnumber Waypoint number. Default at the end.
|
-- @param #number wpnumber Waypoint number. Default at the end.
|
||||||
|
-- @param #number formation Formation the group will use.
|
||||||
-- @param #boolean updateroute If true or nil, call UpdateRoute. If false, no call.
|
-- @param #boolean updateroute If true or nil, call UpdateRoute. If false, no call.
|
||||||
-- @return #number Waypoint index.
|
-- @return #number Waypoint index.
|
||||||
function ARMYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute)
|
function ARMYGROUP:AddWaypoint(coordinate, speed, wpnumber, formation, updateroute)
|
||||||
|
|
||||||
-- Waypoint number. Default is at the end.
|
-- Waypoint number. Default is at the end.
|
||||||
wpnumber=wpnumber or #self.waypoints+1
|
wpnumber=wpnumber or #self.waypoints+1
|
||||||
@ -693,13 +706,16 @@ function ARMYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute)
|
|||||||
local speedkmh=UTILS.KnotsToKmph(speed)
|
local speedkmh=UTILS.KnotsToKmph(speed)
|
||||||
|
|
||||||
-- Create a Naval waypoint.
|
-- Create a Naval waypoint.
|
||||||
local wp=coordinate:WaypointNaval(speedkmh)
|
local wp=coordinate:WaypointGround(speedkmh, formation)
|
||||||
|
|
||||||
-- Add to table.
|
-- Create waypoint data table.
|
||||||
table.insert(self.waypoints, wpnumber, wp)
|
local waypoint=self:_CreateWaypoint(wp)
|
||||||
|
|
||||||
|
-- Add waypoint to table.
|
||||||
|
self:_AddWaypoint(waypoint, wpnumber)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Adding NAVAL waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints))
|
self:T(self.lid..string.format("Adding GROUND waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints))
|
||||||
|
|
||||||
|
|
||||||
-- Update route.
|
-- Update route.
|
||||||
@ -735,7 +751,7 @@ function ARMYGROUP:_InitGroup()
|
|||||||
-- Is (template) group late activated.
|
-- Is (template) group late activated.
|
||||||
self.isLateActivated=self.template.lateActivation
|
self.isLateActivated=self.template.lateActivation
|
||||||
|
|
||||||
-- Naval groups cannot be uncontrolled.
|
-- Ground groups cannot be uncontrolled.
|
||||||
self.isUncontrolled=false
|
self.isUncontrolled=false
|
||||||
|
|
||||||
-- Max speed in km/h.
|
-- Max speed in km/h.
|
||||||
@ -766,6 +782,7 @@ function ARMYGROUP:_InitGroup()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Units of the group.
|
||||||
local units=self.group:GetUnits()
|
local units=self.group:GetUnits()
|
||||||
|
|
||||||
for _,_unit in pairs(units) do
|
for _,_unit in pairs(units) do
|
||||||
@ -847,13 +864,13 @@ function ARMYGROUP:_CheckGroupDone(delay)
|
|||||||
local speed=self:GetSpeedToWaypoint(1)
|
local speed=self:GetSpeedToWaypoint(1)
|
||||||
|
|
||||||
-- Start route at first waypoint.
|
-- Start route at first waypoint.
|
||||||
self:__UpdateRoute(-1, 1, speed, self.depth)
|
self:__UpdateRoute(-1, 1, speed, self.formation)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
self:UpdateRoute(nil, nil, self.depth)
|
self:UpdateRoute(nil, nil, self.formation)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -2537,6 +2537,8 @@ function FLIGHTGROUP:_InitGroup()
|
|||||||
self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC")
|
self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Switch to default formation.
|
||||||
|
-- TODO: Should this be moved to onafterspawned?
|
||||||
self:SwitchFormation(self.formationDefault)
|
self:SwitchFormation(self.formationDefault)
|
||||||
|
|
||||||
-- Add elemets.
|
-- Add elemets.
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
-- @field #NAVYGROUP.IntoWind intowind Into wind info.
|
-- @field #NAVYGROUP.IntoWind intowind Into wind info.
|
||||||
-- @field #table Qintowind Queue of "into wind" turns.
|
-- @field #table Qintowind Queue of "into wind" turns.
|
||||||
-- @field #number depth Ordered depth in meters.
|
-- @field #number depth Ordered depth in meters.
|
||||||
|
-- @field #boolean collisionwarning If true, collition warning.
|
||||||
-- @extends Ops.OpsGroup#OPSGROUP
|
-- @extends Ops.OpsGroup#OPSGROUP
|
||||||
|
|
||||||
--- *Something must be left to chance; nothing is sure in a sea fight above all.* -- Horatio Nelson
|
--- *Something must be left to chance; nothing is sure in a sea fight above all.* -- Horatio Nelson
|
||||||
@ -54,6 +55,7 @@ NAVYGROUP = {
|
|||||||
-- @field #number Speed Speed in knots.
|
-- @field #number Speed Speed in knots.
|
||||||
-- @field #number Offset Offset angle in degrees.
|
-- @field #number Offset Offset angle in degrees.
|
||||||
-- @field #number Id Unique ID of the turn.
|
-- @field #number Id Unique ID of the turn.
|
||||||
|
-- @field Ops.OpsGroup#OPSGROUP.Waypoint waypoint Turn into wind waypoint.
|
||||||
-- @field Core.Point#COORDINATE Coordinate Coordinate where we left the route.
|
-- @field Core.Point#COORDINATE Coordinate Coordinate where we left the route.
|
||||||
-- @field #number Heading Heading the boat will take in degrees.
|
-- @field #number Heading Heading the boat will take in degrees.
|
||||||
-- @field #boolean Open Currently active.
|
-- @field #boolean Open Currently active.
|
||||||
@ -99,8 +101,8 @@ function NAVYGROUP:New(GroupName)
|
|||||||
self:AddTransition("*", "FullStop", "Holding") -- Hold position.
|
self:AddTransition("*", "FullStop", "Holding") -- Hold position.
|
||||||
self:AddTransition("*", "Cruise", "Cruising") -- Hold position.
|
self:AddTransition("*", "Cruise", "Cruising") -- Hold position.
|
||||||
|
|
||||||
self:AddTransition("*", "TurnIntoWind", "*") -- Command the group to turn into the wind.
|
self:AddTransition("*", "TurnIntoWind", "IntoWind") -- Command the group to turn into the wind.
|
||||||
self:AddTransition("*", "TurnIntoWindOver", "*") -- Turn into wind is over.
|
self:AddTransition("*", "TurnIntoWindOver", "Cruising") -- Turn into wind is over.
|
||||||
|
|
||||||
self:AddTransition("*", "TurningStarted", "*") -- Group started turning.
|
self:AddTransition("*", "TurningStarted", "*") -- Group started turning.
|
||||||
self:AddTransition("*", "TurningStopped", "*") -- Group stopped turning.
|
self:AddTransition("*", "TurningStopped", "*") -- Group stopped turning.
|
||||||
@ -108,6 +110,8 @@ function NAVYGROUP:New(GroupName)
|
|||||||
self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards.
|
self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards.
|
||||||
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
|
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
|
||||||
|
|
||||||
|
self:AddTransition("*", "CollitionWarning", "*") -- Collision warning.
|
||||||
|
|
||||||
self:AddTransition("*", "Dive", "Diving") -- Command a submarine to dive.
|
self:AddTransition("*", "Dive", "Diving") -- Command a submarine to dive.
|
||||||
self:AddTransition("Diving", "Surface", "Cruising") -- Command a submarine to go to the surface.
|
self:AddTransition("Diving", "Surface", "Cruising") -- Command a submarine to go to the surface.
|
||||||
|
|
||||||
@ -170,7 +174,7 @@ function NAVYGROUP:SetPatrolAdInfinitum(switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Group patrols ad inifintum. If the last waypoint is reached, it will go to waypoint one and repeat its route.
|
--- Set default cruise speed. This is the speed a group will take by default if no speed is specified explicitly.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @param #number Speed Speed in knots. Default 70% of max speed.
|
-- @param #number Speed Speed in knots. Default 70% of max speed.
|
||||||
-- @return #NAVYGROUP self
|
-- @return #NAVYGROUP self
|
||||||
@ -290,6 +294,36 @@ function NAVYGROUP:AddTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
|||||||
return recovery
|
return recovery
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if the group is currently holding its positon.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #boolean If true, group was ordered to hold.
|
||||||
|
function NAVYGROUP:IsHolding()
|
||||||
|
return self:Is("Holding")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the group is currently cruising.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #boolean If true, group cruising.
|
||||||
|
function NAVYGROUP:IsCruising()
|
||||||
|
return self:Is("Cruising")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the group is currently on a detour.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #boolean If true, group is on a detour
|
||||||
|
function NAVYGROUP:IsOnDetour()
|
||||||
|
return self:Is("OnDetour")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if the group is currently diving.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #boolean If true, group is currently diving.
|
||||||
|
function NAVYGROUP:IsDiving()
|
||||||
|
return self:Is("Diving")
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if the group is currently turning.
|
--- Check if the group is currently turning.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @return #boolean If true, group is currently turning.
|
-- @return #boolean If true, group is currently turning.
|
||||||
@ -354,28 +388,41 @@ function NAVYGROUP:onafterStatus(From, Event, To)
|
|||||||
-- Check if group started or stopped turning.
|
-- Check if group started or stopped turning.
|
||||||
self:_CheckTurning()
|
self:_CheckTurning()
|
||||||
|
|
||||||
-- Check water is ahead.
|
local freepath=10000
|
||||||
local collision=self:_CheckCollisionCoord(pos:Translate(self.collisiondist or 5000, hdg))
|
local collision=false
|
||||||
|
|
||||||
self:_CheckTurnsIntoWind()
|
if not self:IsTurning() then
|
||||||
|
|
||||||
if self.intowind then
|
|
||||||
|
|
||||||
if timer.getAbsTime()>=self.intowind.Tstop then
|
if not self.ispathfinding then
|
||||||
|
|
||||||
self:TurnIntoWindOver()
|
freepath=self:_CheckFreePath(freepath, 100)
|
||||||
|
|
||||||
|
if freepath<5000 then
|
||||||
|
self.ispathfinding=self:_FindPathToNextWaypoint()
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check water is ahead.
|
||||||
|
--collision=self:_CheckCollisionCoord(pos:Translate(freepath+100, hdg))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check into wind queue.
|
||||||
|
self:_CheckTurnsIntoWind()
|
||||||
|
|
||||||
|
-- Check if group got stuck.
|
||||||
|
self:_CheckStuck()
|
||||||
|
|
||||||
-- Get number of tasks and missions.
|
-- Get number of tasks and missions.
|
||||||
local nTaskTot, nTaskSched, nTaskWP=self:CountRemainingTasks()
|
local nTaskTot, nTaskSched, nTaskWP=self:CountRemainingTasks()
|
||||||
local nMissions=self:CountRemainingMissison()
|
local nMissions=self:CountRemainingMissison()
|
||||||
|
|
||||||
|
local intowind=self:IsSteamingIntoWind() and UTILS.SecondsToClock(self.intowind.Tstop-timer.getAbsTime(), true) or "N/A"
|
||||||
|
|
||||||
-- Info text.
|
-- Info text.
|
||||||
local text=string.format("State %s: Wp=%d/%d Speed=%.1f Heading=%03d intowind=%s turning=%s collision=%s Tasks=%d Missions=%d",
|
local text=string.format("%s (T=%d,M=%d): Wp=%d-->%d (of %d) Speed=%.1f (%.1f) Depth=%.1f Hdg=%03d Turn=%s Collision=%d IntoWind=%s ROE=%d AS=%d",
|
||||||
fsmstate, self.currentwp, #self.waypoints, speed, hdg, tostring(self:IsSteamingIntoWind()), tostring(self:IsTurning()), tostring(collision), nTaskTot, nMissions)
|
fsmstate, nTaskTot, nMissions, self.currentwp, self:GetWaypointIndexNext(), #self.waypoints, speed, UTILS.MpsToKnots(self.speed or 0), pos.y, hdg, tostring(self:IsTurning()), freepath, intowind, 0, 0)
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -444,7 +491,7 @@ function NAVYGROUP:onafterStatus(From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Next status update in 10 seconds.
|
||||||
self:__Status(-10)
|
self:__Status(-10)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -510,8 +557,8 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number n Waypoint number. Default is next waypoint.
|
-- @param #number n Waypoint number. Default is next waypoint.
|
||||||
-- @param #number Speed Speed in knots. Default cruise speed.
|
-- @param #number Speed Speed in knots to the next waypoint.
|
||||||
-- @param #number Depth Depth in meters. Default 0 meters.
|
-- @param #number Depth Depth in meters to the next waypoint.
|
||||||
function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
||||||
|
|
||||||
-- Update route from this waypoint number onwards.
|
-- Update route from this waypoint number onwards.
|
||||||
@ -526,52 +573,63 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
-- Waypoints.
|
-- Waypoints.
|
||||||
local waypoints={}
|
local waypoints={}
|
||||||
|
|
||||||
-- Depth for submarines.
|
|
||||||
local depth=Depth or 0
|
|
||||||
|
|
||||||
-- Get current speed in km/h.
|
|
||||||
local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH()
|
|
||||||
|
|
||||||
-- Current waypoint.
|
|
||||||
local current=self:GetCoordinate():WaypointNaval(speed, depth)
|
|
||||||
table.insert(waypoints, current)
|
|
||||||
|
|
||||||
-- Add remaining waypoints to route.
|
-- Add remaining waypoints to route.
|
||||||
|
local depth=nil
|
||||||
for i=n, #self.waypoints do
|
for i=n, #self.waypoints do
|
||||||
|
|
||||||
|
-- Waypoint.
|
||||||
local wp=self.waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
local wp=self.waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||||
|
|
||||||
-- Set speed.
|
-- Check if next wp.
|
||||||
if i==n then
|
if i==n then
|
||||||
|
|
||||||
|
-- Speed.
|
||||||
if Speed then
|
if Speed then
|
||||||
|
-- Take speed specified.
|
||||||
wp.speed=UTILS.KnotsToMps(Speed)
|
wp.speed=UTILS.KnotsToMps(Speed)
|
||||||
elseif self.speedCruise then
|
|
||||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
|
||||||
else
|
|
||||||
-- Take default waypoint speed.
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
if self.speedCruise then
|
|
||||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
|
||||||
else
|
else
|
||||||
-- Take default waypoint speed.
|
-- Take default waypoint speed.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Depth then
|
||||||
|
wp.alt=-Depth
|
||||||
|
elseif self.depth then
|
||||||
|
wp.alt=-self.depth
|
||||||
|
else
|
||||||
|
-- Take default waypoint alt.
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Current set speed in m/s.
|
||||||
|
self.speed=wp.speed
|
||||||
|
|
||||||
|
-- Current set depth.
|
||||||
|
depth=wp.alt
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Dive depth is applied to all other waypoints.
|
||||||
|
if self.depth then
|
||||||
|
wp.alt=-self.depth
|
||||||
|
else
|
||||||
|
-- Take default waypoint depth.
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set depth.
|
|
||||||
wp.alt=-depth --Depth and -Depth or wp.alt
|
|
||||||
|
|
||||||
-- Add waypoint.
|
-- Add waypoint.
|
||||||
table.insert(waypoints, wp)
|
table.insert(waypoints, wp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Current waypoint.
|
||||||
|
local current=self:GetCoordinate():WaypointNaval(UTILS.MpsToKmph(self.speed), depth)
|
||||||
|
table.insert(waypoints, 1, current)
|
||||||
|
|
||||||
|
|
||||||
if #waypoints>1 then
|
if #waypoints>1 then
|
||||||
|
|
||||||
self:I(self.lid..string.format("Updateing route: WP=%d, Speed=%.1f knots, depth=%d meters", #self.waypoints-n+1, UTILS.KmphToKnots(speed), depth))
|
self:I(self.lid..string.format("Updateing route: WP %d-->%d-->%d (#%d), Speed=%.1f knots, Depth=%d m",
|
||||||
|
self.currentwp, n, #self.waypoints, #waypoints-1, UTILS.MpsToKnots(self.speed), depth))
|
||||||
|
|
||||||
|
|
||||||
-- Route group to all defined waypoints remaining.
|
-- Route group to all defined waypoints remaining.
|
||||||
self:Route(waypoints)
|
self:Route(waypoints)
|
||||||
@ -584,11 +642,6 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
|
|||||||
|
|
||||||
self:I(self.lid..string.format("No waypoints left"))
|
self:I(self.lid..string.format("No waypoints left"))
|
||||||
|
|
||||||
if #self.waypoints>1 then
|
|
||||||
self:I(self.lid..string.format("Resuming route at first waypoint"))
|
|
||||||
self:__UpdateRoute(-1, 1, nil, self.depth)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -601,7 +654,7 @@ end
|
|||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where to go.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate where to go.
|
||||||
-- @param #number Speed Speed in knots. Default cruise speed.
|
-- @param #number Speed Speed in knots. Default cruise speed.
|
||||||
-- @param #number Depth Depth in meters. Default 0 meters.
|
-- @param #number Depth Depth in meters. Default 0 meters.
|
||||||
-- @param #number ResumeRoute If true, resume route after detour point was reached.
|
-- @param #number ResumeRoute If true, resume route after detour point was reached. If false, the group will stop at the detour point and wait for futher commands.
|
||||||
function NAVYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Depth, ResumeRoute)
|
function NAVYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Depth, ResumeRoute)
|
||||||
|
|
||||||
-- Waypoints.
|
-- Waypoints.
|
||||||
@ -610,20 +663,18 @@ function NAVYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Depth, Resu
|
|||||||
-- Depth for submarines.
|
-- Depth for submarines.
|
||||||
local depth=Depth or 0
|
local depth=Depth or 0
|
||||||
|
|
||||||
-- Get current speed in km/h.
|
-- Speed in knots.
|
||||||
local speed=Speed and UTILS.KnotsToKmph(Speed) or self.group:GetVelocityKMH()
|
Speed=Speed or self:GetSpeedCruise()
|
||||||
|
|
||||||
-- Current waypoint.
|
local wpindx=self.currentwp+1
|
||||||
local current=self:GetCoordinate():WaypointNaval(speed, depth)
|
|
||||||
table.insert(waypoints, current)
|
|
||||||
|
|
||||||
-- At each waypoint report passing.
|
local wp=self:AddWaypoint(Coordinate, Speed, wpindx, true)
|
||||||
local Task=self.group:TaskFunction("NAVYGROUP._DetourReached", self, ResumeRoute)
|
|
||||||
|
|
||||||
local detour=Coordinate:WaypointNaval(speed, depth, {Task})
|
if ResumeRoute then
|
||||||
table.insert(waypoints, detour)
|
wp.detour=1
|
||||||
|
else
|
||||||
self:Route(waypoints)
|
wp.detour=0
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -662,9 +713,6 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #NAVYGROUP.IntoWind Into wind parameters.
|
-- @param #NAVYGROUP.IntoWind Into wind parameters.
|
||||||
-- @param #number Duration Duration in seconds.
|
|
||||||
-- @param #number Speed Speed in knots.
|
|
||||||
-- @param #boolean Uturn Return to the place we came from.
|
|
||||||
function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
|
function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
|
||||||
|
|
||||||
IntoWind.Heading=self:GetHeadingIntoWind(IntoWind.Offset)
|
IntoWind.Heading=self:GetHeadingIntoWind(IntoWind.Offset)
|
||||||
@ -681,7 +729,7 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
|
|||||||
-- Convert to knots.
|
-- Convert to knots.
|
||||||
vwind=UTILS.MpsToKnots(vwind)
|
vwind=UTILS.MpsToKnots(vwind)
|
||||||
|
|
||||||
-- Speed of carrier in m/s but at least 2 knots.
|
-- Speed of carrier relative to wind but at least 2 knots.
|
||||||
local speed=math.max(IntoWind.Speed-vwind, 2)
|
local speed=math.max(IntoWind.Speed-vwind, 2)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
@ -689,16 +737,28 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
|
|||||||
|
|
||||||
local distance=UTILS.NMToMeters(1000)
|
local distance=UTILS.NMToMeters(1000)
|
||||||
|
|
||||||
local wp={}
|
|
||||||
|
|
||||||
local coord=self:GetCoordinate()
|
local coord=self:GetCoordinate()
|
||||||
local Coord=coord:Translate(distance, IntoWind.Heading)
|
local Coord=coord:Translate(distance, IntoWind.Heading)
|
||||||
|
|
||||||
|
local wpindex=self.currentwp+1 --self:GetWaypointIndexNext(false)
|
||||||
|
|
||||||
|
local wptiw=self:AddWaypoint(Coord, speed, wpindex, true)
|
||||||
|
wptiw.intowind=true
|
||||||
|
|
||||||
|
IntoWind.waypoint=wptiw
|
||||||
|
|
||||||
|
if IntoWind.Uturn then
|
||||||
|
IntoWind.Coordinate:MarkToAll("Return coord")
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local wp={}
|
||||||
wp[1]=coord:WaypointNaval(UTILS.KnotsToKmph(speed))
|
wp[1]=coord:WaypointNaval(UTILS.KnotsToKmph(speed))
|
||||||
wp[2]=Coord:WaypointNaval(UTILS.KnotsToKmph(speed))
|
wp[2]=Coord:WaypointNaval(UTILS.KnotsToKmph(speed))
|
||||||
|
|
||||||
self:Route(wp)
|
self:Route(wp)
|
||||||
|
]]
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "TurnIntoWindOver" event.
|
--- On after "TurnIntoWindOver" event.
|
||||||
@ -711,15 +771,22 @@ end
|
|||||||
-- @param #boolean Uturn Return to the place we came from.
|
-- @param #boolean Uturn Return to the place we came from.
|
||||||
function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To)
|
function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To)
|
||||||
|
|
||||||
|
env.info("FF Turn Into Wind Over!")
|
||||||
|
|
||||||
self.intowind.Over=true
|
self.intowind.Over=true
|
||||||
self.intowind.Open=false
|
self.intowind.Open=false
|
||||||
|
|
||||||
|
-- Remove additional waypoint.
|
||||||
|
self:RemoveWaypointByID(self.intowind.waypoint.uid)
|
||||||
|
|
||||||
if self.intowind.Uturn then
|
if self.intowind.Uturn then
|
||||||
|
env.info("FF Turn Into Wind Over Uturn!")
|
||||||
self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true)
|
self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true)
|
||||||
else
|
else
|
||||||
local indx=self:GetWaypointIndexNext(self.adinfinitum)
|
env.info("FF Turn Into Wind Over Next WP!")
|
||||||
|
local indx=self:GetWaypointIndexNext()
|
||||||
local speed=self:GetWaypointSpeed(indx)
|
local speed=self:GetWaypointSpeed(indx)
|
||||||
self:UpdateRoute(indx, speed, self.depth)
|
self:__UpdateRoute(-1, indx, speed)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.intowind=nil
|
self.intowind=nil
|
||||||
@ -749,10 +816,13 @@ end
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number Speed Speed in knots.
|
-- @param #number Speed Speed in knots until next waypoint is reached.
|
||||||
function NAVYGROUP:onafterCruise(From, Event, To, Speed)
|
function NAVYGROUP:onafterCruise(From, Event, To, Speed)
|
||||||
|
|
||||||
self:UpdateRoute(nil, Speed, self.depth)
|
--
|
||||||
|
self.depth=nil
|
||||||
|
|
||||||
|
self:__UpdateRoute(-1, nil, Speed)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -762,7 +832,8 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number Depth Dive depth in meters. Default 50 meters.
|
-- @param #number Depth Dive depth in meters. Default 50 meters.
|
||||||
function NAVYGROUP:onafterDive(From, Event, To, Depth)
|
-- @param #number Speed Speed in knots until next waypoint is reached.
|
||||||
|
function NAVYGROUP:onafterDive(From, Event, To, Depth, Speed)
|
||||||
|
|
||||||
Depth=Depth or 50
|
Depth=Depth or 50
|
||||||
|
|
||||||
@ -770,7 +841,7 @@ function NAVYGROUP:onafterDive(From, Event, To, Depth)
|
|||||||
|
|
||||||
self.depth=Depth
|
self.depth=Depth
|
||||||
|
|
||||||
self:UpdateRoute(nil, nil, self.depth)
|
self:__UpdateRoute(-1, nil, Speed)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -779,11 +850,12 @@ end
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function NAVYGROUP:onafterSurface(From, Event, To)
|
-- @param #number Speed Speed in knots until next waypoint is reached.
|
||||||
|
function NAVYGROUP:onafterSurface(From, Event, To, Speed)
|
||||||
|
|
||||||
self.depth=0
|
self.depth=0
|
||||||
|
|
||||||
self:UpdateRoute(nil, nil, self.depth)
|
self:__UpdateRoute(-1, nil, Speed)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -959,7 +1031,7 @@ function NAVYGROUP:AddWaypoint(coordinate, speed, wpnumber, updateroute)
|
|||||||
self:_AddWaypoint(waypoint, wpnumber)
|
self:_AddWaypoint(waypoint, wpnumber)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Adding NAVAL waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, speed, self.currentwp, #self.waypoints))
|
self:I(self.lid..string.format("Adding NAVAL waypoint index=%d uid=%d, speed=%.1f knots. Last waypoint passed was #%d. Total waypoints #%d", wpnumber, waypoint.uid, speed, self.currentwp, #self.waypoints))
|
||||||
|
|
||||||
-- Update route.
|
-- Update route.
|
||||||
if updateroute==nil or updateroute==true then
|
if updateroute==nil or updateroute==true then
|
||||||
@ -1089,6 +1161,73 @@ end
|
|||||||
-- Misc Functions
|
-- Misc Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Check for possible collisions between two coordinates.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #number Free distance in meters.
|
||||||
|
function NAVYGROUP:_CheckFreePath(DistanceMax, dx)
|
||||||
|
|
||||||
|
local distance=DistanceMax or 5000
|
||||||
|
local dx=dx or 100
|
||||||
|
|
||||||
|
-- If the group is turning, we cannot really tell anything about a possible collision.
|
||||||
|
if self:IsTurning() then
|
||||||
|
return distance
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Current coordinate.
|
||||||
|
local coordinate=self:GetCoordinate():SetAltitude(0, true)
|
||||||
|
|
||||||
|
-- Current heading.
|
||||||
|
local heading=self:GetHeading()
|
||||||
|
|
||||||
|
local function LoS(dist)
|
||||||
|
local checkcoord=coordinate:Translate(dist, heading, true)
|
||||||
|
return coordinate:IsLOS(checkcoord, 0.001)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- First check if everything is clear.
|
||||||
|
if LoS(DistanceMax) then
|
||||||
|
return DistanceMax
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check()
|
||||||
|
|
||||||
|
local xmin=0
|
||||||
|
local xmax=DistanceMax
|
||||||
|
|
||||||
|
local Nmax=100
|
||||||
|
local eps=100
|
||||||
|
|
||||||
|
local N=1
|
||||||
|
while N<=Nmax do
|
||||||
|
|
||||||
|
local d=xmax-xmin
|
||||||
|
local x=xmin+d/2
|
||||||
|
|
||||||
|
local los=LoS(x)
|
||||||
|
|
||||||
|
env.info(string.format("N=%d: xmin=%.1f xmax=%.1f x=%.1f d=%.3f los=%s", N, xmin, xmax, x, d, tostring(los)))
|
||||||
|
|
||||||
|
if los and d<=eps then
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
|
||||||
|
if los then
|
||||||
|
xmin=x
|
||||||
|
else
|
||||||
|
xmax=x
|
||||||
|
end
|
||||||
|
|
||||||
|
N=N+1
|
||||||
|
end
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return check()
|
||||||
|
end
|
||||||
|
|
||||||
--- Check for possible collisions between two coordinates.
|
--- Check for possible collisions between two coordinates.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @param Core.Point#COORDINATE coordto Coordinate to which the collision is check.
|
-- @param Core.Point#COORDINATE coordto Coordinate to which the collision is check.
|
||||||
@ -1197,6 +1336,32 @@ function NAVYGROUP:_CheckTurning()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if group got stuck.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
function NAVYGROUP:_CheckStuck()
|
||||||
|
|
||||||
|
if self:IsHolding() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local holdtime=0
|
||||||
|
if self.holdtimestamp then
|
||||||
|
holdtime=timer.getTime()-self.holdtimestamp
|
||||||
|
end
|
||||||
|
|
||||||
|
local ExpectedSpeed=self:GetExpectedSpeed()
|
||||||
|
|
||||||
|
local speed=self.group:GetVelocityMPS()
|
||||||
|
|
||||||
|
if speed<0.5 and ExpectedSpeed>0 then
|
||||||
|
if not self.holdtimestamp then
|
||||||
|
self:E(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f expected=%.1f knots", speed, ExpectedSpeed))
|
||||||
|
self.holdtimestamp=timer.getTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if group is done, i.e.
|
--- Check if group is done, i.e.
|
||||||
--
|
--
|
||||||
-- * passed the final waypoint,
|
-- * passed the final waypoint,
|
||||||
@ -1284,6 +1449,14 @@ function NAVYGROUP:_CheckTurnsIntoWind()
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- If into wind, check if over.
|
||||||
|
if self.intowind then
|
||||||
|
if timer.getAbsTime()>=self.intowind.Tstop then
|
||||||
|
self:TurnIntoWindOver()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get default cruise speed.
|
--- Get default cruise speed.
|
||||||
@ -1308,6 +1481,19 @@ function NAVYGROUP:GetSpeedToWaypoint(indx)
|
|||||||
return speed
|
return speed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the currently expected speed.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #number Expected speed in m/s.
|
||||||
|
function NAVYGROUP:GetExpectedSpeed()
|
||||||
|
|
||||||
|
if self:IsHolding() then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return self.speed or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Check queued turns into wind.
|
--- Check queued turns into wind.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @return #NAVYGROUP.IntoWind Next into wind data.
|
-- @return #NAVYGROUP.IntoWind Next into wind data.
|
||||||
@ -1363,6 +1549,85 @@ function NAVYGROUP:GetHeadingIntoWind(Offset)
|
|||||||
return intowind
|
return intowind
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find free path to next waypoint.
|
||||||
|
-- @param #NAVYGROUP self
|
||||||
|
-- @return #boolean If true, a path was found.
|
||||||
|
function NAVYGROUP:_FindPathToNextWaypoint()
|
||||||
|
|
||||||
|
-- Pathfinding A*
|
||||||
|
local astar=ASTAR:New()
|
||||||
|
|
||||||
|
-- Current positon of the group.
|
||||||
|
local position=self:GetCoordinate()
|
||||||
|
|
||||||
|
-- Next waypoint.
|
||||||
|
local wpnext=self:GetWaypointNext()
|
||||||
|
|
||||||
|
-- Next waypoint coordinate.
|
||||||
|
local nextwp=wpnext.coordinate
|
||||||
|
|
||||||
|
-- If we are currently turning into the wind...
|
||||||
|
if wpnext.intowind then
|
||||||
|
local hdg=self:GetHeading()
|
||||||
|
nextwp=position:Translate(UTILS.NMToMeters(20), hdg, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local speed=UTILS.MpsToKnots(wpnext.speed)
|
||||||
|
|
||||||
|
-- Set start coordinate.
|
||||||
|
astar:SetStartCoordinate(position)
|
||||||
|
|
||||||
|
-- Set end coordinate.
|
||||||
|
astar:SetEndCoordinate(nextwp)
|
||||||
|
|
||||||
|
-- Distance to next waypoint.
|
||||||
|
local dist=position:Get2DDistance(nextwp)
|
||||||
|
|
||||||
|
local boxwidth=dist*2
|
||||||
|
local spacex=dist*0.1
|
||||||
|
local delta=dist/10
|
||||||
|
|
||||||
|
-- Create a grid of nodes. We only want nodes of surface type water.
|
||||||
|
astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, false)
|
||||||
|
|
||||||
|
-- Valid neighbour nodes need to have line of sight.
|
||||||
|
astar:SetValidNeighbourLoS(400)
|
||||||
|
|
||||||
|
--- Function to find a path and add waypoints to the group.
|
||||||
|
local function findpath()
|
||||||
|
|
||||||
|
-- Calculate path from start to end node.
|
||||||
|
local path=astar:GetPath(true, true)
|
||||||
|
|
||||||
|
if path then
|
||||||
|
|
||||||
|
-- Loop over nodes in found path.
|
||||||
|
for i,_node in ipairs(path) do
|
||||||
|
local node=_node --Core.Astar#ASTAR.Node
|
||||||
|
|
||||||
|
-- Waypoint index.
|
||||||
|
local wpindex=self:GetWaypointIndexCurrent()+i
|
||||||
|
|
||||||
|
-- Add waypoints along detour path to next waypoint.
|
||||||
|
local wp=self:AddWaypoint(node.coordinate, speed, wpindex)
|
||||||
|
wp.astar=true
|
||||||
|
|
||||||
|
-- Debug: smoke and mark path.
|
||||||
|
node.coordinate:MarkToAll(string.format("Path node #%d", i))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return #path>0
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return findpath()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
--- **Ops** - Generic group enhancement functions.
|
--- **Ops** - Generic group enhancement functions.
|
||||||
--
|
--
|
||||||
|
-- This class is **not** meant to be used itself by the end user.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -48,9 +49,10 @@
|
|||||||
-- @field #boolean detectionOn If true, detected units of the group are analyzed.
|
-- @field #boolean detectionOn If true, detected units of the group are analyzed.
|
||||||
-- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission.
|
-- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission.
|
||||||
--
|
--
|
||||||
-- @field Core.Point#COORDINATE position Current position of the group.
|
-- @field Core.Point#COORDINATE position Position of the group at last status check.
|
||||||
-- @field #number traveldist Distance traveled in meters. This is a lower bound!
|
-- @field #number traveldist Distance traveled in meters. This is a lower bound!
|
||||||
-- @field #number traveltime Time.
|
-- @field #number traveltime Time.
|
||||||
|
-- @field #boolean ispathfinding If true, group is on pathfinding route.
|
||||||
--
|
--
|
||||||
-- @field #number tacanChannelDefault The default TACAN channel.
|
-- @field #number tacanChannelDefault The default TACAN channel.
|
||||||
-- @field #string tacanMorseDefault The default TACAN morse code.
|
-- @field #string tacanMorseDefault The default TACAN morse code.
|
||||||
@ -70,16 +72,22 @@
|
|||||||
-- @field #boolean eplrs If true, EPLRS data link is on.
|
-- @field #boolean eplrs If true, EPLRS data link is on.
|
||||||
--
|
--
|
||||||
-- @field #string roeDefault Default ROE setting.
|
-- @field #string roeDefault Default ROE setting.
|
||||||
-- @field #string rotDefault Default ROT setting.
|
|
||||||
-- @field #string roe Current ROE setting.
|
-- @field #string roe Current ROE setting.
|
||||||
|
--
|
||||||
|
-- @field #string rotDefault Default ROT setting.
|
||||||
-- @field #string rot Current ROT setting.
|
-- @field #string rot Current ROT setting.
|
||||||
--
|
--
|
||||||
|
-- @field #string alarmstateDefault Default Alarm State setting.
|
||||||
|
-- @field #string alarmstate Current Alarm State setting.
|
||||||
|
--
|
||||||
-- @field #number formationDefault Default formation setting.
|
-- @field #number formationDefault Default formation setting.
|
||||||
-- @field #number formation Current formation setting.
|
-- @field #number formation Current formation setting.
|
||||||
--
|
--
|
||||||
|
-- @field Core.Astar#ASTAR Astar path finding.
|
||||||
|
--
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Something must be left to chance; nothing is sure in a sea fight above all.* --- Horatio Nelson
|
--- *A small group of determined and like-minded people can change the course of history.* --- Mahatma Gandhi
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -87,7 +95,7 @@
|
|||||||
--
|
--
|
||||||
-- # The OPSGROUP Concept
|
-- # The OPSGROUP Concept
|
||||||
--
|
--
|
||||||
-- The OPSGROUP class contains common functions used by other classes such as FLIGHGROUP and NAVYGROUP.
|
-- The OPSGROUP class contains common functions used by other classes such as FLIGHGROUP, NAVYGROUP.
|
||||||
--
|
--
|
||||||
-- This class is **not** meant to be used itself by the end user.
|
-- This class is **not** meant to be used itself by the end user.
|
||||||
--
|
--
|
||||||
@ -206,16 +214,18 @@ OPSGROUP.TaskType={
|
|||||||
|
|
||||||
--- Waypoint data.
|
--- Waypoint data.
|
||||||
-- @type OPSGROUP.Waypoint
|
-- @type OPSGROUP.Waypoint
|
||||||
-- @field #table wp DCS waypoint table.
|
|
||||||
-- @field Core.Point#COORDINATE coordinate Waypoint coordinate.
|
|
||||||
-- @field #number speed Speed in m/s.
|
|
||||||
-- @field #number altitude Altitude in meters. For submaries use negative sign for depth.
|
|
||||||
-- @field #number index Waypoint index. This might change as waypoints are added and removed.
|
|
||||||
-- @field #number uid Waypoint's unit id, which is a running number.
|
-- @field #number uid Waypoint's unit id, which is a running number.
|
||||||
-- @field #boolean onroad If true, ground group takes a road.
|
-- @field #number speed Speed in m/s.
|
||||||
-- @field #number formation The formation for this waypoint.
|
-- @field #number alt Altitude in meters. For submaries use negative sign for depth.
|
||||||
-- @field #boolean detour If true, this waypoint is not part of the normal route.
|
|
||||||
-- @field #string action Waypoint action (turning point, etc.). Ground groups have the formation here.
|
-- @field #string action Waypoint action (turning point, etc.). Ground groups have the formation here.
|
||||||
|
-- @field #table task Waypoint task combo.
|
||||||
|
-- @field #string type Waypoint type.
|
||||||
|
-- @field #number x Waypoint x-coordinate.
|
||||||
|
-- @field #number y Waypoint y-coordinate.
|
||||||
|
-- @field #boolean detour If true, this waypoint is not part of the normal route.
|
||||||
|
-- @field #boolean intowind If true, this waypoint is a turn into wind route point.
|
||||||
|
-- @field #boolean astar If true, this waypint was found by A* pathfinding algorithm.
|
||||||
|
-- @field Core.Point#COORDINATE coordinate Waypoint coordinate.
|
||||||
|
|
||||||
--- NavyGroup version.
|
--- NavyGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
@ -433,79 +443,7 @@ function OPSGROUP:GetHeading()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get next waypoint index.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #boolean cyclic If true, return first waypoint if last waypoint was reached. Default is patrol ad infinitum value set.
|
|
||||||
-- @return #number Next waypoint index.
|
|
||||||
function OPSGROUP:GetWaypointIndexNext(cyclic)
|
|
||||||
|
|
||||||
cyclic=cyclic or self.adinfinitum
|
|
||||||
|
|
||||||
local N=#self.waypoints
|
|
||||||
|
|
||||||
local n=math.min(self.currentwp+1, N)
|
|
||||||
|
|
||||||
if cyclic and self.currentwp==N then
|
|
||||||
n=1
|
|
||||||
end
|
|
||||||
|
|
||||||
return n
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get current waypoint index. This is the index of the last passed waypoint.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @return #number Current waypoint index.
|
|
||||||
function OPSGROUP:GetWaypointIndexCurrent()
|
|
||||||
return self.currentwp or 1
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get waypoint speed.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #number indx Waypoint index.
|
|
||||||
-- @return #number Speed set at waypoint in knots.
|
|
||||||
function OPSGROUP:GetWaypointSpeed(indx)
|
|
||||||
|
|
||||||
local waypoint=self:GetWaypoint(indx)
|
|
||||||
|
|
||||||
if waypoint then
|
|
||||||
return UTILS.MpsToKnots(waypoint.speed)
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get waypoint.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #number indx Waypoint index.
|
|
||||||
-- @return #OPSGROUP.Waypoint Waypoint table.
|
|
||||||
function OPSGROUP:GetWaypoint(indx)
|
|
||||||
return self.waypoints[indx]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get final waypoint.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @return #OPSGROUP.Waypoint Final waypoint table.
|
|
||||||
function OPSGROUP:GetWaypointFinal()
|
|
||||||
return self.waypoints[#self.waypoints]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get next waypoint.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #boolean cyclic If true, return first waypoint if last waypoint was reached.
|
|
||||||
-- @return #OPSGROUP.Waypoint Next waypoint table.
|
|
||||||
function OPSGROUP:GetWaypointNext(cyclic)
|
|
||||||
|
|
||||||
local n=self:GetWaypointIndexNext(cyclic)
|
|
||||||
|
|
||||||
return self.waypoints[n]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get current waypoint.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @return #OPSGROUP.Waypoint Current waypoint table.
|
|
||||||
function OPSGROUP:GetWaypointCurrent()
|
|
||||||
return self.waypoints[self.currentwp]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if task description is unique.
|
--- Check if task description is unique.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
@ -524,29 +462,6 @@ function OPSGROUP:CheckTaskDescriptionUnique(description)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get coordinate of next waypoint of the group.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
|
|
||||||
-- @return #number Number of waypoint.
|
|
||||||
function OPSGROUP:GetNextWaypointCoordinate()
|
|
||||||
|
|
||||||
-- Next waypoint.
|
|
||||||
local n=self:GetWaypointIndexNext(cyclic)
|
|
||||||
|
|
||||||
-- Next waypoint.
|
|
||||||
local wp=self.waypoints[n]
|
|
||||||
|
|
||||||
return self:GetWaypointCoordinate(wp)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get next waypoint coordinates.
|
|
||||||
-- @param #OPSGROUP self
|
|
||||||
-- @param #table wp Waypoint table.
|
|
||||||
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
|
|
||||||
function OPSGROUP:GetWaypointCoordinate(wp)
|
|
||||||
-- TODO: move this to COORDINATE class.
|
|
||||||
return COORDINATE:New(wp.x, wp.alt, wp.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Activate a *late activated* group.
|
--- Activate a *late activated* group.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
@ -707,6 +622,111 @@ function OPSGROUP:GetWaypointIndex(uid)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get next waypoint index.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #boolean cyclic If true, return first waypoint if last waypoint was reached. Default is patrol ad infinitum value set.
|
||||||
|
-- @return #number Next waypoint index.
|
||||||
|
function OPSGROUP:GetWaypointIndexNext(cyclic)
|
||||||
|
|
||||||
|
if cyclic==nil then
|
||||||
|
cyclic=self.adinfinitum
|
||||||
|
end
|
||||||
|
|
||||||
|
--env.info("FF cyclic = "..tostring(cyclic))
|
||||||
|
|
||||||
|
local N=#self.waypoints
|
||||||
|
|
||||||
|
local n=math.min(self.currentwp+1, N)
|
||||||
|
|
||||||
|
--env.info("FF n = "..tostring(n))
|
||||||
|
|
||||||
|
if cyclic and self.currentwp==N then
|
||||||
|
n=1
|
||||||
|
--env.info("FF cyclic n = "..tostring(n))
|
||||||
|
end
|
||||||
|
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get current waypoint index. This is the index of the last passed waypoint.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #number Current waypoint index.
|
||||||
|
function OPSGROUP:GetWaypointIndexCurrent()
|
||||||
|
return self.currentwp or 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get waypoint.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #number indx Waypoint index.
|
||||||
|
-- @return #OPSGROUP.Waypoint Waypoint table.
|
||||||
|
function OPSGROUP:GetWaypoint(indx)
|
||||||
|
return self.waypoints[indx]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get final waypoint.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP.Waypoint Final waypoint table.
|
||||||
|
function OPSGROUP:GetWaypointFinal()
|
||||||
|
return self.waypoints[#self.waypoints]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get next waypoint.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #boolean cyclic If true, return first waypoint if last waypoint was reached.
|
||||||
|
-- @return #OPSGROUP.Waypoint Next waypoint table.
|
||||||
|
function OPSGROUP:GetWaypointNext(cyclic)
|
||||||
|
|
||||||
|
local n=self:GetWaypointIndexNext(cyclic)
|
||||||
|
|
||||||
|
return self.waypoints[n]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get current waypoint.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #OPSGROUP.Waypoint Current waypoint table.
|
||||||
|
function OPSGROUP:GetWaypointCurrent()
|
||||||
|
return self.waypoints[self.currentwp]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get coordinate of next waypoint of the group.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
|
||||||
|
function OPSGROUP:GetNextWaypointCoordinate()
|
||||||
|
|
||||||
|
-- Get next waypoint
|
||||||
|
local waypoint=self:GetWaypointNext(cyclic)
|
||||||
|
|
||||||
|
return waypoint.coordinate
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get waypoint coordinates.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #number index Waypoint index.
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
|
||||||
|
function OPSGROUP:GetWaypointCoordinate(index)
|
||||||
|
local waypoint=self:GetWaypoint(index)
|
||||||
|
if waypoint then
|
||||||
|
return waypoint.coordinate
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get waypoint speed.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #number indx Waypoint index.
|
||||||
|
-- @return #number Speed set at waypoint in knots.
|
||||||
|
function OPSGROUP:GetWaypointSpeed(indx)
|
||||||
|
|
||||||
|
local waypoint=self:GetWaypoint(indx)
|
||||||
|
|
||||||
|
if waypoint then
|
||||||
|
return UTILS.MpsToKnots(waypoint.speed)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Remove a waypoint with a ceratin UID.
|
--- Remove a waypoint with a ceratin UID.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #number uid Waypoint UID.
|
-- @param #number uid Waypoint UID.
|
||||||
@ -716,8 +736,7 @@ function OPSGROUP:RemoveWaypointByID(uid)
|
|||||||
local index=self:GetWaypointIndex(uid)
|
local index=self:GetWaypointIndex(uid)
|
||||||
|
|
||||||
if index then
|
if index then
|
||||||
self:RemoveWaypoint(index)
|
self:RemoveWaypoint(index)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -741,24 +760,47 @@ function OPSGROUP:RemoveWaypoint(wpindex)
|
|||||||
local n=#self.waypoints
|
local n=#self.waypoints
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(self.lid..string.format("Removing waypoint %d. N %d-->%d", wpindex, N, n))
|
self:I(self.lid..string.format("Removing waypoint index %d, current wp index %d. N %d-->%d", wpindex, self.currentwp, N, n))
|
||||||
|
|
||||||
-- Waypoint was not reached yet.
|
-- Waypoint was not reached yet.
|
||||||
if wpindex > self.currentwp then
|
if wpindex > self.currentwp then
|
||||||
|
|
||||||
-- Could be that we just removed the only remaining waypoint ==> passedfinalwp=true so we RTB or wait.
|
-- Could be that we just removed the only remaining waypoint ==> passedfinalwp=true.
|
||||||
|
|
||||||
|
-- TODO: patrol adinfinitum.
|
||||||
|
|
||||||
if self.currentwp>=n then
|
if self.currentwp>=n then
|
||||||
self.passedfinalwp=true
|
self.passedfinalwp=true
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_CheckGroupDone()
|
|
||||||
|
|
||||||
|
env.info("FF passed final waypoint after remove current wp = "..self.currentwp)
|
||||||
|
|
||||||
|
self:_CheckGroupDone(1)
|
||||||
|
|
||||||
|
--elseif wpindex==self.currentwp then
|
||||||
|
|
||||||
|
-- Removed the waypoint we just passed.
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- If an already passed waypoint was deleted, we do not need to update the route.
|
-- If an already passed waypoint was deleted, we do not need to update the route.
|
||||||
|
|
||||||
-- TODO: But what about the self.currentwp number. This is now incorrect!
|
-- If current wp = 1 it stays 1. Otherwise decrease current wp.
|
||||||
self.currentwp=self.currentwp-1
|
|
||||||
|
if self.currentwp==1 then
|
||||||
|
|
||||||
|
if self.adinfinitum then
|
||||||
|
self.currentwp=#self.waypoints
|
||||||
|
else
|
||||||
|
self.currentwp=1
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
self.currentwp=self.currentwp-1
|
||||||
|
end
|
||||||
|
|
||||||
|
--self.currentwp=math.max(1, self.currentwp-1)
|
||||||
|
env.info("FF current waypoint after remove "..self.currentwp)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -995,9 +1037,9 @@ end
|
|||||||
|
|
||||||
--- Get the unfinished waypoint tasks
|
--- Get the unfinished waypoint tasks
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #number n Waypoint index. Counting starts at one.
|
-- @param #number id Unique waypoint ID.
|
||||||
-- @return #table Table of tasks. Table could also be empty {}.
|
-- @return #table Table of tasks. Table could also be empty {}.
|
||||||
function OPSGROUP:GetTasksWaypoint(n)
|
function OPSGROUP:GetTasksWaypoint(id)
|
||||||
|
|
||||||
-- Tasks table.
|
-- Tasks table.
|
||||||
local tasks={}
|
local tasks={}
|
||||||
@ -1008,7 +1050,7 @@ function OPSGROUP:GetTasksWaypoint(n)
|
|||||||
-- Look for first task that SCHEDULED.
|
-- Look for first task that SCHEDULED.
|
||||||
for _,_task in pairs(self.taskqueue) do
|
for _,_task in pairs(self.taskqueue) do
|
||||||
local task=_task --#OPSGROUP.Task
|
local task=_task --#OPSGROUP.Task
|
||||||
if task.type==OPSGROUP.TaskType.WAYPOINT and task.status==OPSGROUP.TaskStatus.SCHEDULED and task.waypoint==n then
|
if task.type==OPSGROUP.TaskType.WAYPOINT and task.status==OPSGROUP.TaskStatus.SCHEDULED and task.waypoint==id then
|
||||||
table.insert(tasks, task)
|
table.insert(tasks, task)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1913,19 +1955,48 @@ end
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #number n Waypoint passed.
|
|
||||||
-- @param #number N Total number of waypoints.
|
|
||||||
-- @param #OPSGROUP.Waypoint Waypoint Waypoint data passed.
|
-- @param #OPSGROUP.Waypoint Waypoint Waypoint data passed.
|
||||||
function OPSGROUP:onafterPassingWaypoint(From, Event, To, n, N, Waypoint)
|
function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
|
||||||
local text=string.format("Group passed waypoint %d/%d", n, N)
|
|
||||||
self:T(self.lid..text)
|
|
||||||
MESSAGE:New(text, 30, "DEBUG"):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
|
-- Apply tasks of this waypoint.
|
||||||
|
local ntasks=self:_SetWaypointTasks(Waypoint)
|
||||||
|
|
||||||
|
-- Get waypoint index.
|
||||||
|
local wpindex=self:GetWaypointIndex(Waypoint.uid)
|
||||||
|
|
||||||
|
-- Final waypoint reached?
|
||||||
|
if wpindex==nil or wpindex==#self.waypoints then
|
||||||
|
|
||||||
|
-- Set switch to true.
|
||||||
|
self.passedfinalwp=true
|
||||||
|
|
||||||
|
-- Check if all tasks/mission are done? If so, RTB or WAIT.
|
||||||
|
-- Note, we delay it for a second to let the OnAfterPassingwaypoint function to be executed in case someone wants to add another waypoint there.
|
||||||
|
if ntasks==0 then
|
||||||
|
self:_CheckGroupDone(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Group passed waypoint %s/%d ID=%d: final=%s detour=%s astar=%s",
|
||||||
|
tostring(wpindex), #self.waypoints, Waypoint.uid, tostring(self.passedfinalwp), tostring(Waypoint.detour), tostring(Waypoint.astar))
|
||||||
|
self:I(self.lid..text)
|
||||||
|
MESSAGE:New(text, 30, "DEBUG"):ToAllIf(self.Debug)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "GotoWaypoint" event. Group will got to the given waypoint and execute its route from there.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #OPSGROUP.Waypoint Waypoint The waypoint.
|
||||||
|
-- @return #number Number of tasks.
|
||||||
|
function OPSGROUP:_SetWaypointTasks(Waypoint)
|
||||||
|
|
||||||
-- Get all waypoint tasks.
|
-- Get all waypoint tasks.
|
||||||
local tasks=self:GetTasksWaypoint(Waypoint.uid)
|
local tasks=self:GetTasksWaypoint(Waypoint.uid)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
local text=string.format("WP %d/%d tasks:", n, N)
|
local text=string.format("WP uid=%d tasks:", Waypoint.uid)
|
||||||
if #tasks>0 then
|
if #tasks>0 then
|
||||||
for i,_task in pairs(tasks) do
|
for i,_task in pairs(tasks) do
|
||||||
local task=_task --#OPSGROUP.Task
|
local task=_task --#OPSGROUP.Task
|
||||||
@ -1963,20 +2034,8 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, n, N, Waypoint)
|
|||||||
if #taskswp>0 then
|
if #taskswp>0 then
|
||||||
self:SetTask(self.group:TaskCombo(taskswp))
|
self:SetTask(self.group:TaskCombo(taskswp))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Final AIR waypoint reached?
|
|
||||||
if n==N then
|
|
||||||
|
|
||||||
-- Set switch to true.
|
return #taskswp
|
||||||
self.passedfinalwp=true
|
|
||||||
|
|
||||||
-- Check if all tasks/mission are done? If so, RTB or WAIT.
|
|
||||||
-- Note, we delay it for a second to let the OnAfterPassingwaypoint function to be executed in case someone wants to add another waypoint there.
|
|
||||||
if #taskswp==0 then
|
|
||||||
self:_CheckGroupDone(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "GotoWaypoint" event. Group will got to the given waypoint and execute its route from there.
|
--- On after "GotoWaypoint" event. Group will got to the given waypoint and execute its route from there.
|
||||||
@ -2195,14 +2254,17 @@ end
|
|||||||
|
|
||||||
--- Initialize Mission Editor waypoints.
|
--- Initialize Mission Editor waypoints.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #table waypoint DCS waypoint data table.
|
-- @param #OPSGROUP.Waypoint waypoint DCS waypoint data table.
|
||||||
-- @return #OPSGROUP.Waypoint Waypoint data.
|
-- @return #OPSGROUP.Waypoint Waypoint data.
|
||||||
function OPSGROUP:_CreateWaypoint(waypoint, detour, onroad, formation)
|
function OPSGROUP:_CreateWaypoint(waypoint, formation, detour)
|
||||||
|
|
||||||
waypoint.uid=self.wpcounter
|
waypoint.uid=self.wpcounter
|
||||||
waypoint.coordinate=COORDINATE:New(waypoint.x, waypoint.alt, waypoint.y)
|
waypoint.coordinate=COORDINATE:New(waypoint.x, waypoint.alt, waypoint.y)
|
||||||
waypoint.detour=detour and detour or false
|
waypoint.detour=detour and detour or false
|
||||||
waypoint.formation=formation
|
waypoint.formation=formation
|
||||||
|
if formation then
|
||||||
|
waypoint.action=formation
|
||||||
|
end
|
||||||
waypoint.onroad=onroad and onroad or false
|
waypoint.onroad=onroad and onroad or false
|
||||||
|
|
||||||
self.wpcounter=self.wpcounter+1
|
self.wpcounter=self.wpcounter+1
|
||||||
@ -2218,7 +2280,7 @@ function OPSGROUP:_AddWaypoint(waypoint, wpnumber)
|
|||||||
|
|
||||||
wpnumber=wpnumber or #self.waypoints+1
|
wpnumber=wpnumber or #self.waypoints+1
|
||||||
|
|
||||||
env.info(string.format("adding waypoint at index=%d", wpnumber))
|
self:I(self.lid..string.format("Adding waypoint at index=%d id=%d", wpnumber, waypoint.uid))
|
||||||
|
|
||||||
-- Add waypoint to table.
|
-- Add waypoint to table.
|
||||||
table.insert(self.waypoints, wpnumber, waypoint)
|
table.insert(self.waypoints, wpnumber, waypoint)
|
||||||
@ -2263,7 +2325,7 @@ end
|
|||||||
--- Route group along waypoints.
|
--- Route group along waypoints.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #table waypoints Table of waypoints.
|
-- @param #table waypoints Table of waypoints.
|
||||||
-- @default
|
-- @param #number delay Delay in seconds.
|
||||||
-- @return #OPSGROUP self
|
-- @return #OPSGROUP self
|
||||||
function OPSGROUP:Route(waypoints, delay)
|
function OPSGROUP:Route(waypoints, delay)
|
||||||
|
|
||||||
@ -2314,13 +2376,13 @@ function OPSGROUP:_UpdateWaypointTasks(n)
|
|||||||
if i>=n or nwaypoints==1 then
|
if i>=n or nwaypoints==1 then
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Updating waypoint task for waypoint %d/%d. Last waypoint passed %d", i, nwaypoints, self.currentwp))
|
self:I(self.lid..string.format("Updating waypoint task for waypoint %d/%d ID=%d. Last waypoint passed %d", i, nwaypoints, wp.uid, self.currentwp))
|
||||||
|
|
||||||
-- Tasks of this waypoint
|
-- Tasks of this waypoint
|
||||||
local taskswp={}
|
local taskswp={}
|
||||||
|
|
||||||
-- At each waypoint report passing.
|
-- At each waypoint report passing.
|
||||||
local TaskPassingWaypoint=self.group:TaskFunction("OPSGROUP._PassingWaypoint", self, i, wp.uid)
|
local TaskPassingWaypoint=self.group:TaskFunction("OPSGROUP._PassingWaypoint", self, wp.uid)
|
||||||
table.insert(taskswp, TaskPassingWaypoint)
|
table.insert(taskswp, TaskPassingWaypoint)
|
||||||
|
|
||||||
-- Waypoint task combo.
|
-- Waypoint task combo.
|
||||||
@ -2337,26 +2399,72 @@ end
|
|||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Function called when a group is passing a waypoint.
|
--- Function called when a group is passing a waypoint.
|
||||||
--@param Wrapper.Group#GROUP group Group that passed the waypoint
|
--@param Wrapper.Group#GROUP group Group that passed the waypoint.
|
||||||
--@param #OPSGROUP opsgroup Ops group object.
|
--@param #OPSGROUP opsgroup Ops group object.
|
||||||
--@param #number i Waypoint number that has been reached.
|
|
||||||
--@param #number uid Waypoint UID.
|
--@param #number uid Waypoint UID.
|
||||||
function OPSGROUP._PassingWaypoint(group, opsgroup, i, uid)
|
function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
|
||||||
|
|
||||||
local final=#opsgroup.waypoints or 1
|
|
||||||
|
|
||||||
-- Debug message.
|
|
||||||
local text=string.format("Group passing waypoint %d of %d, uid=%d", i, final, uid)
|
|
||||||
opsgroup:I(opsgroup.lid..text)
|
|
||||||
|
|
||||||
-- Set current waypoint.
|
|
||||||
opsgroup.currentwp=i
|
|
||||||
|
|
||||||
-- Get waypoint data.
|
-- Get waypoint data.
|
||||||
local waypoint=opsgroup:GetWaypointByID(uid)
|
local waypoint=opsgroup:GetWaypointByID(uid)
|
||||||
|
|
||||||
-- Trigger PassingWaypoint event.
|
if waypoint then
|
||||||
opsgroup:PassingWaypoint(i, final, waypoint)
|
|
||||||
|
-- Get the current waypoint index.
|
||||||
|
opsgroup.currentwp=opsgroup:GetWaypointIndex(uid)
|
||||||
|
|
||||||
|
-- Set expected speed and formation from the next WP.
|
||||||
|
local wpnext=opsgroup:GetWaypointNext()
|
||||||
|
if wpnext then
|
||||||
|
|
||||||
|
-- Set formation.
|
||||||
|
if opsgroup.isGround then
|
||||||
|
opsgroup.formation=wpnext.action
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set speed.
|
||||||
|
opsgroup.speed=wpnext.speed
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if the group is still pathfinding.
|
||||||
|
if opsgroup.ispathfinding and not waypoint.astar then
|
||||||
|
opsgroup.ispathfinding=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check special waypoints.
|
||||||
|
if waypoint.astar then
|
||||||
|
|
||||||
|
env.info("FF removing Astar waypoint "..uid)
|
||||||
|
opsgroup:RemoveWaypointByID(uid)
|
||||||
|
|
||||||
|
elseif waypoint.detour then
|
||||||
|
|
||||||
|
env.info("FF removing Detour waypoint "..uid)
|
||||||
|
opsgroup:RemoveWaypointByID(uid)
|
||||||
|
|
||||||
|
-- Trigger event.
|
||||||
|
opsgroup:DetourReached()
|
||||||
|
|
||||||
|
if waypoint.detour==0 then
|
||||||
|
opsgroup:FullStop()
|
||||||
|
elseif waypoint.detour==1 then
|
||||||
|
opsgroup:Cruise()
|
||||||
|
else
|
||||||
|
opsgroup:E("ERROR: waypoint.detour should be 0 or 1")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Group passing waypoint uid=%d", uid)
|
||||||
|
opsgroup:I(opsgroup.lid..text)
|
||||||
|
|
||||||
|
-- Trigger PassingWaypoint event.
|
||||||
|
if not (waypoint.astar or waypoint.detour) then
|
||||||
|
opsgroup:PassingWaypoint(waypoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2461,6 +2569,52 @@ function OPSGROUP:SetOptionROT(rot)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the default Alarm State for the group. This is the state gets when the group is spawned or to which it defaults back after a mission.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #number alarmstate Alarm state of group. Default is `AI.Option.Ground.val.ALARM_STATE.AUTO` (0).
|
||||||
|
-- @return #OPSGROUP self
|
||||||
|
function OPSGROUP:SetDefaultAlarmstate(alarmstate)
|
||||||
|
self.alarmstateDefault=alarmstate or 0
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set current Alarm State of the group.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #string alarmstate Alarm state of group. Default is the value defined by :SetDefaultAlarmstate().
|
||||||
|
-- @return #OPSGROUP self
|
||||||
|
function OPSGROUP:SetOptionAlarmstate(alarmstate)
|
||||||
|
|
||||||
|
self.alarmstate=alarmstate or self.alarmstateDefault
|
||||||
|
|
||||||
|
if self:IsAlive() then
|
||||||
|
|
||||||
|
if self.alarmstate==0 then
|
||||||
|
self.group:OptionAlarmStateAuto()
|
||||||
|
elseif self.alarmstate==1 then
|
||||||
|
self.group:OptionAlarmStateGreen()
|
||||||
|
elseif self.alarmstate==2 then
|
||||||
|
self.group:OptionAlarmStateRed()
|
||||||
|
else
|
||||||
|
self:E("ERROR: Unknown Alarm State! Setting to AUTO.")
|
||||||
|
self.group:OptionAlarmStateAuto()
|
||||||
|
end
|
||||||
|
|
||||||
|
self:I(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.alarmstate))
|
||||||
|
else
|
||||||
|
-- TODO WARNING
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get current Alarm State of the group.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @return #number Current Alarm State.
|
||||||
|
function OPSGROUP:GetAlarmstate()
|
||||||
|
return self.alarmstate
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Element and Group Status Functions
|
-- Element and Group Status Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -222,6 +222,15 @@ ENUMS.Formation.RotaryWing.EchelonLeft={}
|
|||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081
|
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081
|
||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082
|
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082
|
||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083
|
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083
|
||||||
|
ENUMS.Formation.Vehicle={}
|
||||||
|
ENUMS.Formation.Vehicle.Vee="Vee"
|
||||||
|
ENUMS.Formation.Vehicle.EchelonRight="EchelonR"
|
||||||
|
ENUMS.Formation.Vehicle.OffRoad="Off Road"
|
||||||
|
ENUMS.Formation.Vehicle.Rank="Rank"
|
||||||
|
ENUMS.Formation.Vehicle.EchelonLeft="EchelonL"
|
||||||
|
ENUMS.Formation.Vehicle.OnRoad="On Road"
|
||||||
|
ENUMS.Formation.Vehicle.Cone="Cone"
|
||||||
|
ENUMS.Formation.Vehicle.Diamond="Diamond"
|
||||||
|
|
||||||
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
||||||
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user