#ZONE_RADIUS

* Added `ZONE_RADIUS:GetRandomCoordinateWithoutBuildings(...)`

#MARKEROPS_BASE
* Added Class
This commit is contained in:
Applevangelist 2022-08-30 14:36:18 +02:00
parent 5277cca4e1
commit 7ef69208d4
3 changed files with 332 additions and 1 deletions

View File

@ -0,0 +1,251 @@
--- **Core** - MarkerOps_Base.
--
-- **Main Features:**
--
-- * Create an easy way to tap into markers added to the F10 map by users.
-- * Recognize own tag and list of keywords.
-- * Matched keywords are handed down to functions.
--
-- ===
--
-- ### Author: **Applevangelist**
--
-- Date: 5 May 2021
--
-- ===
---
-- @module Core.MarkerOps_Base
-- @image MOOSE_Core.JPG
--------------------------------------------------------------------------
-- MARKEROPS_BASE Class Definition.
--------------------------------------------------------------------------
--- MARKEROPS_BASE class.
-- @type MARKEROPS_BASE
-- @field #string ClassName Name of the class.
-- @field #string Tag Tag to identify commands.
-- @field #table Keywords Table of keywords to recognize.
-- @field #string version Version of #MARKEROPS_BASE.
-- @extends Core.Fsm#FSM
--- *Fiat lux.* -- Latin proverb.
--
-- ===
--
-- # The MARKEROPS_BASE Concept
--
-- This class enable scripting text-based actions from markers.
--
-- @field #MARKEROPS_BASE
MARKEROPS_BASE = {
ClassName = "MARKEROPS",
Tag = "mytag",
Keywords = {},
version = "0.0.1",
debug = false,
}
--- Function to instantiate a new #MARKEROPS_BASE object.
-- @param #MARKEROPS_BASE self
-- @param #string Tagname Name to identify us from the event text.
-- @param #table Keywords Table of keywords recognized from the event text.
-- @return #MARKEROPS_BASE self
function MARKEROPS_BASE:New(Tagname,Keywords)
-- Inherit FSM
local self=BASE:Inherit(self, FSM:New()) -- #MARKEROPS_BASE
-- Set some string id for output to DCS.log file.
self.lid=string.format("MARKEROPS_BASE %s | ", tostring(self.version))
self.Tag = Tagname or "mytag"-- #string
self.Keywords = Keywords or {} -- #table - might want to use lua regex here, too
self.debug = false
-----------------------
--- FSM Transitions ---
-----------------------
-- Start State.
self:SetStartState("Stopped")
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start the FSM.
self:AddTransition("*", "MarkAdded", "*") -- Start the FSM.
self:AddTransition("*", "MarkChanged", "*") -- Start the FSM.
self:AddTransition("*", "MarkDeleted", "*") -- Start the FSM.
self:AddTransition("Running", "Stop", "Stopped") -- Stop the FSM.
self:HandleEvent(EVENTS.MarkAdded, self.OnEventMark)
self:HandleEvent(EVENTS.MarkChange, self.OnEventMark)
self:HandleEvent(EVENTS.MarkRemoved, self.OnEventMark)
-- start
self:I(self.lid..string.format("started for %s",self.Tag))
self:__Start(1)
return self
-------------------
-- PSEUDO Functions
-------------------
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
--- "Stop" trigger. Used to stop the function an unhandle events
-- @function [parent=#MARKEROPS_BASE] Stop
end
--- (internal) Handle events.
-- @param #MARKEROPS_BASE self
-- @param Core.Event#EVENTDATA Event
function MARKEROPS_BASE:OnEventMark(Event)
self:T({Event})
if Event == nil or Event.idx == nil then
self:E("Skipping onEvent. Event or Event.idx unknown.")
return true
end
--position
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
local coord=COORDINATE:NewFromVec3(vec3)
if self.debug then
local coordtext = coord:ToStringLLDDM()
local text = tostring(Event.text)
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
end
-- decision
if Event.id==world.event.S_EVENT_MARK_ADDED then
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
-- Handle event
local Eventtext = tostring(Event.text)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkAdded(Eventtext,matchtable,coord)
end
end
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
-- Handle event.
local Eventtext = tostring(Event.text)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkChanged(Eventtext,matchtable,coord)
end
end
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
-- Hande event.
local Eventtext = tostring(Event.text)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
self:MarkDeleted()
end
end
end
end
--- (internal) Match tag.
-- @param #MARKEROPS_BASE self
-- @param #string Eventtext Text added to the marker.
-- @return #boolean
function MARKEROPS_BASE:_MatchTag(Eventtext)
local matches = false
local type = string.lower(self.Tag) -- #string
if string.find(string.lower(Eventtext),type) then
matches = true --event text contains tag
end
return matches
end
--- (internal) Match keywords table.
-- @param #MARKEROPS_BASE self
-- @param #string Eventtext Text added to the marker.
-- @return #table
function MARKEROPS_BASE:_MatchKeywords(Eventtext)
local matchtable = {}
local keytable = self.Keywords
for _index,_word in pairs (keytable) do
if string.find(string.lower(Eventtext),string.lower(_word))then
table.insert(matchtable,_word)
end
end
return matchtable
end
--- On before "MarkAdded" event. Triggered when a Marker is added to the F10 map.
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
end
--- On before "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
end
--- On before "MarkDeleted" event. Triggered when a Marker is removed from the F10 map.
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
function MARKEROPS_BASE:onbeforeMarkDeleted(From,Event,To)
self:T({self.lid,From,Event,To})
end
--- On enter "Stopped" event. Unsubscribe events.
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
function MARKEROPS_BASE:onenterStopped(From,Event,To)
self:T({self.lid,From,Event,To})
-- unsubscribe from events
self:UnHandleEvent(EVENTS.MarkAdded)
self:UnHandleEvent(EVENTS.MarkChange)
self:UnHandleEvent(EVENTS.MarkRemoved)
end
--------------------------------------------------------------------------
-- MARKEROPS_BASE Class Definition End.
--------------------------------------------------------------------------

View File

@ -1295,7 +1295,86 @@ function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
return Coordinate
end
--- Returns a @{Core.Point#COORDINATE} object reflecting a random location within the zone where there are no **map objects** of type "Building".
-- Does not find statics you might have placed there. **Note** This might be quite CPU intensive, use with care.
-- @param #ZONE_RADIUS self
-- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0m.
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
-- @param #number distance (Optional) Minumum distance from any building coordinate. Defaults to 100m.
-- @param #boolean markbuildings (Optional) Place markers on found buildings (if any).
-- @param #boolean markfinal (Optional) Place marker on the final coordinate (if any).
-- @return Core.Point#COORDINATE The random coordinate or `nil` if cannot be found in 1000 iterations.
function ZONE_RADIUS:GetRandomCoordinateWithoutBuildings(inner,outer,distance,markbuildings,markfinal)
local dist = distance or 100
local objects = {}
if self.ScanData and self.ScanData.Scenery then
objects = self:GetScannedScenery()
else
self:Scan({Object.Category.SCENERY})
objects = self:GetScannedScenery()
end
local T0 = timer.getTime()
local T1 = timer.getTime()
local buildings = {}
if self.ScanData and self.ScanData.BuildingCoordinates then
buildings = self.ScanData.BuildingCoordinates
else
-- build table of buildings coordinates
for _,_object in pairs (objects) do
for _,_scen in pairs (_object) do
local scenery = _scen -- Wrapper.Scenery#SCENERY
local description=scenery:GetDesc()
if description and description.attributes and description.attributes.Buildings then
if markbuildings then
MARKER:New(scenery:GetCoordinate(),"Building"):ToAll()
end
buildings[#buildings+1] = scenery:GetCoordinate()
end
end
end
self.ScanData.BuildingCoordinates = buildings
end
-- max 1000 tries
local rcoord = nil
local found = false
local iterations = 0
for i=1,1000 do
iterations = iterations + 1
rcoord = self:GetRandomCoordinate(inner,outer)
found = false
for _,_coord in pairs (buildings) do
local coord = _coord -- Core.Point#COORDINATE
-- keep >50m dist from buildings
if coord:Get2DDistance(rcoord) > dist then
found = true
else
found = false
end
end
if found then
-- we have a winner!
if markfinal then
MARKER:New(rcoord,"FREE"):ToAll()
end
break
end
end
T1=timer.getTime()
self:T(string.format("Found a coordinate: %s | Iterations: %d | Time: %d",tostring(found),iterations,T1-T0))
if found then return rcoord else return nil end
end
--- @type ZONE
-- @extends #ZONE_RADIUS

View File

@ -28,6 +28,7 @@ __Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
__Moose.Include( 'Scripts/Moose/Core/MarkerOps_Base.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )