diff --git a/Moose Development/Moose/Core/Astar.lua b/Moose Development/Moose/Core/Astar.lua index 05dd4d800..ece354492 100644 --- a/Moose Development/Moose/Core/Astar.lua +++ b/Moose Development/Moose/Core/Astar.lua @@ -166,7 +166,7 @@ ASTAR.INF=1/0 --- ASTAR class version. -- @field #string version -ASTAR.version="0.4.0" +ASTAR.version="0.5.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -174,6 +174,7 @@ ASTAR.version="0.4.0" -- TODO: Add more valid neighbour functions. -- TODO: Write docs. +-- DONE: Add pathlines for seach/valid neighbours. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -789,6 +790,42 @@ function ASTAR:FindClosestPathline(Coordinate) return pathline, dist, vec3, S end +--- Find the closest node to the given coordinate. +-- @param #ASTAR self +-- @param Core.Point#COORDINATE Coord Reference coordinate. +-- @param #table ExcludeNodes Nodes that are excluded. +-- @return #ASTAR.Node The node that was fround +function ASTAR:_FindClosestTerminalNode(Coord, ExcludeNodes) + + -- Find the closest pathline to the ref coordinate. + local pathline, dist, vec3, s=self:FindClosestPathline(Coord) + + -- Find the closest node to the given start coordinate. + local node, dist2=self:FindClosestNode(Coord) + + if pathline and vec3 and dist and dist2>dist then + + -- Create a node on the closest pathline so we first go straight there and then along the pathline. + local node=self:AddNodeFromCoordinate(COORDINATE:NewFromVec3(vec3)) + + -- We also need the pathline point. + local point=pathline:AddPointFromVec3(vec3, nil, s.p1) + + node.pathline=pathline + node.pathpoint=point + + self:T2(self.lid..string.format("Added new node=%d, which is closest to start coord. dist=%.1f m", node.id, dist)) + end + + -- Find the closest node to the given start coordinate. + local Node, dist3=self:FindClosestNode(Coord, ExcludeNodes) + + -- Debug info. + self:T(self.lid..string.format("CLOSEST node ID=%d, distance=%.1f", Node.id, dist3)) + + return Node, dist3 +end + --- Find the start node. -- @param #ASTAR self @@ -885,8 +922,14 @@ end -- @return #table Table of nodes from start to finish. function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode) - self:FindStartNode() - self:FindEndNode() +-- self:FindStartNode() +-- self:FindEndNode() + + -- Find start Node (closest node to start coordinate). + self.startNode=self:_FindClosestTerminalNode(self.startCoord) + + -- Find end node, which is not the start node (excluded). + self.endNode=self:_FindClosestTerminalNode(self.endCoord, {self.startNode}) local nodes=self.nodes local start=self.startNode @@ -924,22 +967,6 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode) -- Get current node. local current=self:_LowestFscore(openset, f_score) - -- Debug --- self:I("FF current node="..current.id) --- self:I("FF came_from") --- for _neighbour,_current in pairs(came_from) do --- local neighbour=_neighbour --#ASTAR.Node --- local current=_current --#ASTAR.Node --- self:I(string.format("neighbour=%d --> %d=current", neighbour.id, current.id)) --- end --- local text="Path:" --- local path=self:_UnwindPath({}, came_from, current) --- for i,_node in pairs(path) do --- local node=_node --#ASTAR.Node --- text=text..string.format("\n[%d] Node=%d", i, node.id) --- end --- self:I(text) - -- Check if we are at the end node. if current.id==goal.id then @@ -984,14 +1011,7 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode) -- Get neighbour nodes. local neighbors=self:_NeighbourNodes(current, nodes) - --- local text=string.format("Current node UID=%d pathline=%s", current.id, current.pathline and current.pathline.name or "N/A") --- for _,_node in pairs(neighbors) do --- local node=_node --#ASTAR.Node --- text=text..string.format("\nNeighbour node UID=%d pathline=%s", node.id, node.pathline and node.pathline.name or "N/A") --- end --- self:T(self.lid..text) - + -- Loop over neighbours. for _,neighbor in pairs(neighbors) do diff --git a/Moose Development/Moose/Core/Pathline.lua b/Moose Development/Moose/Core/Pathline.lua index 5254e759d..8aac6c7c4 100644 --- a/Moose Development/Moose/Core/Pathline.lua +++ b/Moose Development/Moose/Core/Pathline.lua @@ -513,6 +513,11 @@ function PATHLINE:GetClosestPoint3D(Vec3) local D=math.huge local S={} --#PATHLINE.Segment + if not Vec3 then + self:E(self.lid.."ERROR: input Vec3 is nil!") + return nil, nil, nil + end + for i=2,#self.points do local A=self.points[i-1] --#PATHLINE.Point @@ -531,8 +536,7 @@ function PATHLINE:GetClosestPoint3D(Vec3) local f=proj/lab/lab -- Debug info. - local text=string.format("FF Proj=%.1f, |ab|=%.1f, f=%.1f", proj, lab, f) - self:T(self.lid..text) + self:T(self.lid..string.format("Proj=%.1f, |ab|=%.1f, f=%.1f", proj, lab, f)) -- Cases for finite segment. local p=nil --DCS#Vec2 diff --git a/Moose Development/Moose/Ops/FlightControl.lua b/Moose Development/Moose/Ops/FlightControl.lua index 9566168b0..9fec0aa43 100644 --- a/Moose Development/Moose/Ops/FlightControl.lua +++ b/Moose Development/Moose/Ops/FlightControl.lua @@ -4152,6 +4152,51 @@ function FLIGHTCONTROL:_CheckFlights() -- Current flight status. local flightstatus=self:GetFlightStatus(flight) + + + --- + -- Track flight + --- + if true then + + for _,_element in pairs(flight.elements) do + local element=_element --Ops.OpsGroup#OPSGROUP.Element + + local unit=element.unit + + if unit and unit:IsAlive() then + + local coord=unit:GetCoord() + local vec3=coord:GetVec3() + + if vec3 and element.pos then + + local id=UTILS.GetMarkID() + + trigger.action.lineToAll(-1, id, vec3, element.pos, {1,1,1,0.5}, 1) + + end + + if coord then + local taxipath, dist, tpcoord, seg=self.airbase:GetClosestTaxiway(coord) + + if taxipath then + local text=string.format("Flight %s [%s/%s]: Unit %s close to taxiway %s. Dist=%.1f meters, Segment=%s-%s", flight:GetName(), flight:GetState(), self:GetFlightStatus(flight), + element.name, taxipath:GetName(), dist, seg.p1.name, seg.p2.name) + MESSAGE:New(text,10):ToAll():ToLog() + end + + end + + -- Store last position. + element.pos=vec3 + + end + + end + + end + if not flight.isAI then -- Check if speeding while taxiing. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 065d88bf3..048c7d4da 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -61,6 +61,7 @@ -- @field #boolean jettisonWeapons Allow (true) or disallow (false) AI to jettison weapons if in danger. -- @field #table flightplans Flight plans for this group. -- @field Navigation.FlightPlan#FLIGHTPLAN flightplan Currently active flight plan. +-- @field Core.Pathline#PATHLINE taxipath Assigned taxi pathline. -- -- @extends Ops.OpsGroup#OPSGROUP diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index c69e9666e..7510a5be1 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -1201,15 +1201,32 @@ end --- Add a taxiway from a given PATHLINE. -- @param #AIRBASE self --- @param Core.Pathline#PATHLINE TaxiPathline Pathline of the taxi way. --- @param #string Name Name of the taxi way, *e.g.* "Alpha", or "Alpha-Kilo". --- @return #boolean If `true`, silent mode is enabled. +-- @param Core.Pathline#PATHLINE TaxiPathline Pathline of the taxi way or name of pathline as #string. +-- @param #string Name Name of the taxi way, *e.g.* "Alpha", or "Alpha-Kilo". Default is name of pathline. +-- @return #AIRBASE self function AIRBASE:AddTaxiway(TaxiPathline, Name) + -- If passed as string, get pathline. + if type(TaxiPathline)=="string" then + TaxiPathline=PATHLINE:FindByName(TaxiPathline) + end + + -- Set name. Name=Name or TaxiPathline:GetName() - self.taxiways[Name]=TaxiPathline + -- Create a deep copy. + local taxiway=UTILS.DeepCopy(TaxiPathline) --Core.Pathline#PATHLINE + + -- Set name. + taxiway.name=Name + -- Add to taxiways. + self.taxiways[Name]=taxiway + + + --self:I(self.taxiways) + + return self end @@ -1250,6 +1267,38 @@ function AIRBASE:FindTaxiwaysFromAtoB(StartCoord, EndCoord) return taxipath, taxiways end +--- Get closest taxiway from a given reference coordinate. +-- @param #AIRBASE self +-- @param Core.Point#COORDINATE Coord Reference coordinate. +-- @return Core.Pathline#PATHLINE Taxiway. +-- @return #number Distance to taxiway in meters. +-- @return Core.Point#COORDINATE Coordinate on taxiway closest to reference coordinate. +-- @return Core.Pathline#PATHLINE.Segment Segment of the taxiway closest to the reference coordinate. +function AIRBASE:GetClosestTaxiway(Coord) + + local taxipath=nil + local distmin=math.huge + local coordmin=nil + local segmin=nil + + for name,_pathline in pairs(self.taxiways) do + local pathline=_pathline --Core.Pathline#PATHLINE + + local coord, dist, segment=pathline:GetClosestPoint3D(Coord) + + if dist