From 3bb36044c1724ea30c5b75ce3b0f99c75006b507 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 25 Jul 2022 22:45:43 +0200 Subject: [PATCH 1/2] OPS - Added check that cohorts cannot have the same name. - Made clearer that cohorts cannot have the same name in the docs. --- Moose Development/Moose/Ops/Flotilla.lua | 2 +- Moose Development/Moose/Ops/Legion.lua | 16 +++++++++++----- Moose Development/Moose/Ops/Platoon.lua | 2 +- Moose Development/Moose/Ops/Squadron.lua | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Ops/Flotilla.lua b/Moose Development/Moose/Ops/Flotilla.lua index 55e44e9b6..adc13b73e 100644 --- a/Moose Development/Moose/Ops/Flotilla.lua +++ b/Moose Development/Moose/Ops/Flotilla.lua @@ -57,7 +57,7 @@ FLOTILLA.version="0.1.0" -- @param #FLOTILLA self -- @param #string TemplateGroupName Name of the template group. -- @param #number Ngroups Number of asset groups of this flotilla. Default 3. --- @param #string FlotillaName Name of the flotilla, e.g. "VFA-37". +-- @param #string FlotillaName Name of the flotilla. Must be **unique**! -- @return #FLOTILLA self function FLOTILLA:New(TemplateGroupName, Ngroups, FlotillaName) diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 01e35dc3b..366d6a7d5 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -66,7 +66,7 @@ LEGION.version="0.3.4" --- Create a new LEGION class object. -- @param #LEGION self -- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse. --- @param #string LegionName Name of the legion. +-- @param #string LegionName Name of the legion. Must be **unique**! -- @return #LEGION self function LEGION:New(WarehouseName, LegionName) @@ -396,11 +396,17 @@ end -- @param Ops.Cohort#COHORT Cohort The cohort to be added. -- @return #LEGION self function LEGION:AddCohort(Cohort) - - -- TODO: Check if this cohort is already part of the legion! - -- Add cohort to legion. - table.insert(self.cohorts, Cohort) + if self:IsCohort(Cohort.name) then + + self:E(self.lid..string.format("ERROR: A cohort with name %s already exists in this legion. Cohorts must have UNIQUE names!")) + + else + + -- Add cohort to legion. + table.insert(self.cohorts, Cohort) + + end return self end diff --git a/Moose Development/Moose/Ops/Platoon.lua b/Moose Development/Moose/Ops/Platoon.lua index 6d6a3e87a..8b380a134 100644 --- a/Moose Development/Moose/Ops/Platoon.lua +++ b/Moose Development/Moose/Ops/Platoon.lua @@ -56,7 +56,7 @@ PLATOON.version="0.1.0" -- @param #PLATOON self -- @param #string TemplateGroupName Name of the template group. -- @param #number Ngroups Number of asset groups of this platoon. Default 3. --- @param #string PlatoonName Name of the platoon, e.g. "VFA-37". +-- @param #string PlatoonName Name of the platoon. Must be **unique**! -- @return #PLATOON self function PLATOON:New(TemplateGroupName, Ngroups, PlatoonName) diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index e720de2cc..dc2188a3e 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -93,7 +93,7 @@ SQUADRON.version="0.8.1" -- @param #SQUADRON self -- @param #string TemplateGroupName Name of the template group. -- @param #number Ngroups Number of asset groups of this squadron. Default 3. --- @param #string SquadronName Name of the squadron, e.g. "VFA-37". +-- @param #string SquadronName Name of the squadron, e.g. "VFA-37". Must be **unique**! -- @return #SQUADRON self function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) From 9c83d5e7526cb7be778bbc055bb8e95d29dfc769 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 31 Jul 2022 01:13:42 +0200 Subject: [PATCH 2/2] ZONE - Added new class `ZONE_ELASTIC` --- Moose Development/Moose/Core/Point.lua | 24 +- Moose Development/Moose/Core/Timer.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 325 +++++++++++++++++++++++-- 3 files changed, 324 insertions(+), 27 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 4df755ea7..6d6ac18df 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -2278,7 +2278,7 @@ do -- COORDINATE end --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. - -- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 10 points** in total are supported. + -- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 15 points** in total are supported. -- @param #COORDINATE self -- @param #table Coordinates Table of coordinates of the remaining points of the shape. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. @@ -2331,8 +2331,28 @@ do -- COORDINATE trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==10 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "") + elseif #vecs==11 then + trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], + vecs[11], + Color, FillColor, LineType, ReadOnly, Text or "") + elseif #vecs==12 then + trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], + vecs[11], vecs[12], + Color, FillColor, LineType, ReadOnly, Text or "") + elseif #vecs==13 then + trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], + vecs[11], vecs[12], vecs[13], + Color, FillColor, LineType, ReadOnly, Text or "") + elseif #vecs==14 then + trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], + vecs[11], vecs[12], vecs[13], vecs[14], + Color, FillColor, LineType, ReadOnly, Text or "") + elseif #vecs==15 then + trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], + vecs[11], vecs[12], vecs[13], vecs[14], vecs[15], + Color, FillColor, LineType, ReadOnly, Text or "") else - self:E("ERROR: Currently a free form polygon can only have 10 points in total!") + self:E("ERROR: Currently a free form polygon can only have 15 points in total!") -- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :( trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "") end diff --git a/Moose Development/Moose/Core/Timer.lua b/Moose Development/Moose/Core/Timer.lua index 2d01d5c17..88e1e77b3 100644 --- a/Moose Development/Moose/Core/Timer.lua +++ b/Moose Development/Moose/Core/Timer.lua @@ -167,7 +167,7 @@ function TIMER:Start(Tstart, dT, Duration) local Tnow=timer.getTime() -- Start time in sec. - self.Tstart=Tstart and Tnow+Tstart or Tnow+0.001 -- one millisecond delay if Tstart=nil + self.Tstart=Tstart and Tnow+math.max(Tstart, 0.001) or Tnow+0.001 -- one millisecond delay if Tstart=nil -- Set time interval. self.dT=dT diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 3164b95bf..ddc6b3e0c 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -59,6 +59,8 @@ -- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. -- @field #number DrawID Unique ID of the drawn zone on the F10 map. -- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value. +-- @field #table FillColor Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value. +-- @field #number drawCoalition Draw coalition. -- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID! -- @field #number Surface Type of surface. Only determined at the center of the zone! -- @extends Core.Fsm#FSM @@ -357,6 +359,22 @@ function ZONE_BASE:BoundZone() end +--- Set draw coalition of zone. +-- @param #ZONE_BASE self +-- @param #number Coalition Coalition. Default -1. +-- @return #ZONE_BASE self +function ZONE_BASE:SetDrawCoalition(Coalition) + self.drawCoalition=Coalition or -1 + return self +end + +--- Get draw coalition of zone. +-- @param #ZONE_BASE self +-- @return #number Draw coaliton. +function ZONE_BASE:GetDrawCoalition() + return self.drawCoalition or -1 +end + --- Set color of zone. -- @param #ZONE_BASE self -- @param #table RGBcolor RGB color table. Default `{1, 0, 0}`. @@ -402,6 +420,51 @@ function ZONE_BASE:GetColorAlpha() return alpha end +--- Set fill color of zone. +-- @param #ZONE_BASE self +-- @param #table RGBcolor RGB color table. Default `{1, 0, 0}`. +-- @param #number Alpha Transparacy between 0 and 1. Default 0.15. +-- @return #ZONE_BASE self +function ZONE_BASE:SetFillColor(RGBcolor, Alpha) + + RGBcolor=RGBcolor or {1, 0, 0} + Alpha=Alpha or 0.15 + + self.FillColor={} + self.FillColor[1]=RGBcolor[1] + self.FillColor[2]=RGBcolor[2] + self.FillColor[3]=RGBcolor[3] + self.FillColor[4]=Alpha + + return self +end + +--- Get fill color table of the zone. +-- @param #ZONE_BASE self +-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value. +function ZONE_BASE:GetFillColor() + return self.FillColor +end + +--- Get RGB fill color of zone. +-- @param #ZONE_BASE self +-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code. +function ZONE_BASE:GetFillColorRGB() + local rgb={} + rgb[1]=self.FillColor[1] + rgb[2]=self.FillColor[2] + rgb[3]=self.FillColor[3] + return rgb +end + +--- Get transperency Alpha fill value of zone. +-- @param #ZONE_BASE self +-- @return #number Alpha value. +function ZONE_BASE:GetFillColorAlpha() + local alpha=self.FillColor[4] + return alpha +end + --- Remove the drawing of the zone from the F10 map. -- @param #ZONE_BASE self -- @param #number Delay (Optional) Delay before the drawing is removed. @@ -1858,7 +1921,7 @@ function ZONE_POLYGON_BASE:BoundZone( UnBound ) end ---- Draw the zone on the F10 map. **NOTE** Currently, only polygons with **exactly four points** are supported! +--- Draw the zone on the F10 map. **NOTE** Currently, only polygons **up to ten points** are supported! -- @param #ZONE_POLYGON_BASE self -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red. @@ -1870,33 +1933,48 @@ end -- @return #ZONE_POLYGON_BASE self function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) - local coordinate=COORDINATE:NewFromVec2(self._.Polygon[1]) + if self._.Polygon and #self._.Polygon>=3 then - Color=Color or self:GetColorRGB() - Alpha=Alpha or 1 + local coordinate=COORDINATE:NewFromVec2(self._.Polygon[1]) + + Coalition=Coalition or self:GetDrawCoalition() + + -- Set draw coalition. + self:SetDrawCoalition(Coalition) - FillColor=FillColor or UTILS.DeepCopy(Color) - FillAlpha=FillAlpha or self:GetColorAlpha() - - - if #self._.Polygon==4 then - - local Coord2=COORDINATE:NewFromVec2(self._.Polygon[2]) - local Coord3=COORDINATE:NewFromVec2(self._.Polygon[3]) - local Coord4=COORDINATE:NewFromVec2(self._.Polygon[4]) - - self.DrawID=coordinate:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) - - else - - local Coordinates=self:GetVerticiesCoordinates() - table.remove(Coordinates, 1) - - self.DrawID=coordinate:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) - + Color=Color or self:GetColorRGB() + Alpha=Alpha or 1 + + -- Set color. + self:SetColor(Color, Alpha) + + FillColor=FillColor or self:GetFillColorRGB() + if not FillColor then UTILS.DeepCopy(Color) end + FillAlpha=FillAlpha or self:GetFillColorAlpha() + if not FillAlpha then FillAlpha=0.15 end + + -- Set fill color. + self:SetFillColor(FillColor, FillAlpha) + + if #self._.Polygon==4 then + + local Coord2=COORDINATE:NewFromVec2(self._.Polygon[2]) + local Coord3=COORDINATE:NewFromVec2(self._.Polygon[3]) + local Coord4=COORDINATE:NewFromVec2(self._.Polygon[4]) + + self.DrawID=coordinate:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) + + else + + local Coordinates=self:GetVerticiesCoordinates() + table.remove(Coordinates, 1) + + self.DrawID=coordinate:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) + + end + end - return self end @@ -2229,6 +2307,205 @@ function ZONE_POLYGON:FindByName( ZoneName ) return ZoneFound end +do -- ZONE_ELASTIC + + --- @type ZONE_ELASTIC + -- @field #table points Points in 2D. + -- @field #table setGroups Set of GROUPs. + -- @field #table setOpsGroups Set of OPSGROUPS. + -- @field #table setUnits Set of UNITs. + -- @field #number updateID Scheduler ID for updating. + -- @extends #ZONE_POLYGON_BASE + + --- The ZONE_ELASTIC class defines a dynamic polygon zone, where only the convex hull is used. + -- + -- @field #ZONE_ELASTIC + ZONE_ELASTIC = { + ClassName="ZONE_ELASTIC", + points={}, + setGroups={} + } + + --- Constructor to create a ZONE_ELASTIC instance. + -- @param #ZONE_ELASTIC self + -- @param #string ZoneName Name of the zone. + -- @param DCS#Vec2 Points (Optional) Fixed points. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:New(ZoneName, Points) + + local self=BASE:Inherit(self, ZONE_POLYGON_BASE:New(ZoneName, Points)) --#ZONE_ELASTIC + + -- Zone objects are added to the _DATABASE and SET_ZONE objects. + _EVENTDISPATCHER:CreateEventNewZone( self ) + + if Points then + self.points=Points + end + + return self + end + + --- Add a vertex (point) to the polygon. + -- @param #ZONE_ELASTIC self + -- @param DCS#Vec2 Vec2 Point in 2D (with x and y coordinates). + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:AddVertex2D(Vec2) + + -- Add vec2 to points. + table.insert(self.points, Vec2) + + return self + end + + + --- Add a vertex (point) to the polygon. + -- @param #ZONE_ELASTIC self + -- @param DCS#Vec3 Vec3 Point in 3D (with x, y and z coordinates). Only the x and z coordinates are used. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:AddVertex3D(Vec3) + + -- Add vec2 from vec3 to points. + table.insert(self.points, {x=Vec3.x, y=Vec3.z}) + + return self + end + + + --- Add a set of groups. Positions of the group will be considered as polygon vertices when contructing the convex hull. + -- @param #ZONE_ELASTIC self + -- @param Core.Set#SET_GROUP SetGroup Set of groups. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:AddSetGroup(GroupSet) + + -- Add set to table. + table.insert(self.setGroups, GroupSet) + + return self + end + + + --- Update the convex hull of the polygon. + -- This uses the [Graham scan](https://en.wikipedia.org/wiki/Graham_scan). + -- @param #ZONE_ELASTIC self + -- @field #number Delay Delay in seconds before the zone is updated. Default 0. + -- @field #boolean Draw Draw the zone. Default `nil`. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:Update(Delay, Draw) + + -- Debug info. + self:T(string.format("Updating ZONE_ELASTIC %s", tostring(self.ZoneName))) + + -- Copy all points. + local points=UTILS.DeepCopy(self.points or {}) + + if self.setGroups then + for _,_setGroup in pairs(self.setGroups) do + local setGroup=_setGroup --Core.Set#SET_GROUP + for _,_group in pairs(setGroup.Set) do + local group=_group --Wrapper.Group#GROUP + if group and group:IsAlive() then + table.insert(points, group:GetVec2()) + end + end + end + end + + -- Update polygon verticies from points. + self._.Polygon=self:_ConvexHull(points) + + if Draw~=false then + if self.DrawID or Draw==true then + self:UndrawZone() + self:DrawZone() + end + end + + end + + --- Start the updating scheduler. + -- @param #ZONE_ELASTIC self + -- @param #number Tstart Time in seconds before the updating starts. + -- @param #number dT Time interval in seconds between updates. Default 60 sec. + -- @param #number Tstop Time in seconds after which the updating stops. Default `nil`. + -- @field #boolean Draw Draw the zone. Default `nil`. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:StartUpdate(Tstart, dT, Tstop, Draw) + + self.updateID=self:ScheduleRepeat(Tstart, dT, 0, Tstop, ZONE_ELASTIC.Update, self, 0, Draw) + + return self + end + + --- Stop the updating scheduler. + -- @param #ZONE_ELASTIC self + -- @param #number Delay Delay in seconds before the scheduler will be stopped. Default 0. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:StopUpdate(Delay) + + if Delay and Delay>0 then + self:ScheduleOnce(Delay, ZONE_ELASTIC.StopUpdate, self) + else + + if self.updateID then + + self:ScheduleStop(self.updateID) + + self.updateID=nil + + end + + end + + return self + end + + + --- Create a convec hull. + -- @param #ZONE_ELASTIC self + -- @param #table pl Points + -- @return #table Points + function ZONE_ELASTIC:_ConvexHull(pl) + + if #pl == 0 then + return {} + end + + table.sort(pl, function(left,right) + return left.x < right.x + end) + + local h = {} + + -- Function: ccw > 0 if three points make a counter-clockwise turn, clockwise if ccw < 0, and collinear if ccw = 0. + local function ccw(a,b,c) + return (b.x - a.x) * (c.y - a.y) > (b.y - a.y) * (c.x - a.x) + end + + -- lower hull + for i,pt in pairs(pl) do + while #h >= 2 and not ccw(h[#h-1], h[#h], pt) do + table.remove(h,#h) + end + table.insert(h,pt) + end + + -- upper hull + local t = #h + 1 + for i=#pl, 1, -1 do + local pt = pl[i] + while #h >= t and not ccw(h[#h-1], h[#h], pt) do + table.remove(h, #h) + end + table.insert(h, pt) + end + + table.remove(h, #h) + + return h + end + +end + do -- ZONE_AIRBASE --- @type ZONE_AIRBASE