funkyfranky d61840d834 Added Big Smoke Effect
Added big smoke effects to COORDINATE API.
2018-05-11 12:27:55 +02:00

497 lines
13 KiB
Lua

--- This module contains derived utilities taken from the MIST framework,
-- which are excellent tools to be reused in an OO environment!.
--
-- ### Authors:
--
-- * Grimes : Design & Programming of the MIST framework.
--
-- ### Contributions:
--
-- * FlightControl : Rework to OO framework
--
-- @module Utils
--- @type SMOKECOLOR
-- @field Green
-- @field Red
-- @field White
-- @field Orange
-- @field Blue
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
--- @type FLARECOLOR
-- @field Green
-- @field Red
-- @field White
-- @field Yellow
FLARECOLOR = trigger.flareColor -- #FLARECOLOR
--- Big smoke preset enum.
-- @type BIGSMOKEPRESET
BIGSMOKEPRESET = {
SmallSmokeAndFire=0,
MediumSmokeAndFire=1,
LargeSmokeAndFire=2,
HugeSmokeAndFire=3,
SmallSmoke=4,
MediumSmoke=5,
LargeSmoke=6,
HugeSmoke=7,
}
--- Utilities static class.
-- @type UTILS
UTILS = {
_MarkID = 1
}
--- Function to infer instance of an object
--
-- ### Examples:
--
-- * UTILS.IsInstanceOf( 'some text', 'string' ) will return true
-- * UTILS.IsInstanceOf( some_function, 'function' ) will return true
-- * UTILS.IsInstanceOf( 10, 'number' ) will return true
-- * UTILS.IsInstanceOf( false, 'boolean' ) will return true
-- * UTILS.IsInstanceOf( nil, 'nil' ) will return true
--
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', ZONE ) will return true
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'ZONE' ) will return true
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'zone' ) will return true
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'BASE' ) will return true
--
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'GROUP' ) will return false
--
--
-- @param object is the object to be evaluated
-- @param className is the name of the class to evaluate (can be either a string or a Moose class)
-- @return #boolean
UTILS.IsInstanceOf = function( object, className )
-- Is className NOT a string ?
if not type( className ) == 'string' then
-- Is className a Moose class ?
if type( className ) == 'table' and className.IsInstanceOf ~= nil then
-- Get the name of the Moose class as a string
className = className.ClassName
-- className is neither a string nor a Moose class, throw an error
else
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
local err_str = 'className parameter should be a string; parameter received: '..type( className )
return false
-- error( err_str )
end
end
-- Is the object a Moose class instance ?
if type( object ) == 'table' and object.IsInstanceOf ~= nil then
-- Use the IsInstanceOf method of the BASE class
return object:IsInstanceOf( className )
else
-- If the object is not an instance of a Moose class, evaluate against lua basic data types
local basicDataTypes = { 'string', 'number', 'function', 'boolean', 'nil', 'table' }
for _, basicDataType in ipairs( basicDataTypes ) do
if className == basicDataType then
return type( object ) == basicDataType
end
end
end
-- Check failed
return false
end
--from http://lua-users.org/wiki/CopyTable
UTILS.DeepCopy = function(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
local objectreturn = _copy(object)
return objectreturn
end
-- porting in Slmod's serialize_slmod2
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
lookup_table = {}
local function _Serialize( tbl )
if type(tbl) == 'table' then --function only works for tables!
if lookup_table[tbl] then
return lookup_table[object]
end
local tbl_str = {}
lookup_table[tbl] = tbl_str
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
local ind_str = {}
if type(ind) == "number" then
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = tostring(ind)
ind_str[#ind_str + 1] = ']='
else --must be a string
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind)
ind_str[#ind_str + 1] = ']='
end
local val_str = {}
if ((type(val) == 'number') or (type(val) == 'boolean')) then
val_str[#val_str + 1] = tostring(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'string' then
val_str[#val_str + 1] = routines.utils.basicSerialize(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'nil' then -- won't ever happen, right?
val_str[#val_str + 1] = 'nil,'
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'table' then
if ind == "__index" then
-- tbl_str[#tbl_str + 1] = "__index"
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
val_str[#val_str + 1] = _Serialize(val)
val_str[#val_str + 1] = ',' --I think this is right, I just added it
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
end
elseif type(val) == 'function' then
tbl_str[#tbl_str + 1] = "f() " .. tostring(ind)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
local objectreturn = _Serialize(tbl)
return objectreturn
end
--porting in Slmod's "safestring" basic serialize
UTILS.BasicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
UTILS.ToDegree = function(angle)
return angle*180/math.pi
end
UTILS.ToRadian = function(angle)
return angle*math.pi/180
end
UTILS.MetersToNM = function(meters)
return meters/1852
end
UTILS.MetersToFeet = function(meters)
return meters/0.3048
end
UTILS.NMToMeters = function(NM)
return NM*1852
end
UTILS.FeetToMeters = function(feet)
return feet*0.3048
end
UTILS.KnotsToKmph = function(knots)
return knots* 1.852
end
UTILS.KmphToMps = function( kmph )
return kmph / 3.6
end
UTILS.MpsToKmph = function( mps )
return mps * 3.6
end
UTILS.MiphToMps = function( miph )
return miph * 0.44704
end
UTILS.MpsToMiph = function( mps )
return mps / 0.44704
end
UTILS.MpsToKnots = function( mps )
return mps * 3600 / 1852
end
UTILS.KnotsToMps = function( knots )
return knots * 1852 / 3600
end
UTILS.CelciusToFarenheit = function( Celcius )
return Celcius * 9/5 + 32
end
--[[acc:
in DM: decimal point of minutes.
In DMS: decimal point of seconds.
position after the decimal of the least significant digit:
So:
42.32 - acc of 2.
]]
UTILS.tostringLL = function( lat, lon, acc, DMS)
local latHemi, lonHemi
if lat > 0 then
latHemi = 'N'
else
latHemi = 'S'
end
if lon > 0 then
lonHemi = 'E'
else
lonHemi = 'W'
end
lat = math.abs(lat)
lon = math.abs(lon)
local latDeg = math.floor(lat)
local latMin = (lat - latDeg)*60
local lonDeg = math.floor(lon)
local lonMin = (lon - lonDeg)*60
if DMS then -- degrees, minutes, and seconds.
local oldLatMin = latMin
latMin = math.floor(latMin)
local latSec = UTILS.Round((oldLatMin - latMin)*60, acc)
local oldLonMin = lonMin
lonMin = math.floor(lonMin)
local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc)
if latSec == 60 then
latSec = 0
latMin = latMin + 1
end
if lonSec == 60 then
lonSec = 0
lonMin = lonMin + 1
end
local secFrmtStr -- create the formatting string for the seconds place
secFrmtStr = '%02d'
-- if acc <= 0 then -- no decimal place.
-- secFrmtStr = '%02d'
-- else
-- local width = 3 + acc -- 01.310 - that's a width of 6, for example.
-- secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
-- end
return string.format('%03d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
.. string.format('%03d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
else -- degrees, decimal minutes.
latMin = UTILS.Round(latMin, acc)
lonMin = UTILS.Round(lonMin, acc)
if latMin == 60 then
latMin = 0
latDeg = latDeg + 1
end
if lonMin == 60 then
lonMin = 0
lonDeg = lonDeg + 1
end
local minFrmtStr -- create the formatting string for the minutes place
if acc <= 0 then -- no decimal place.
minFrmtStr = '%02d'
else
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
minFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
end
return string.format('%03d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
.. string.format('%03d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
end
end
-- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5.
UTILS.tostringMGRS = function(MGRS, acc) --R2.1
if acc == 0 then
return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph
else
return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', UTILS.Round(MGRS.Easting/(10^(5-acc)), 0))
.. ' ' .. string.format('%0' .. acc .. 'd', UTILS.Round(MGRS.Northing/(10^(5-acc)), 0))
end
end
--- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
function UTILS.Round( num, idp )
local mult = 10 ^ ( idp or 0 )
return math.floor( num * mult + 0.5 ) / mult
end
-- porting in Slmod's dostring
function UTILS.DoString( s )
local f, err = loadstring( s )
if f then
return true, f()
else
return false, err
end
end
-- Here is a customized version of pairs, which I called spairs because it iterates over the table in a sorted order.
function UTILS.spairs( t, order )
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k end
-- if order function given, sort by it by passing the table and keys a, b,
-- otherwise just sort the keys
if order then
table.sort(keys, function(a,b) return order(t, a, b) end)
else
table.sort(keys)
end
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
-- get a new mark ID for markings
function UTILS.GetMarkID()
UTILS._MarkID = UTILS._MarkID + 1
return UTILS._MarkID
end
-- Test if a Vec2 is in a radius of another Vec2
function UTILS.IsInRadius( InVec2, Vec2, Radius )
local InRadius = ( ( InVec2.x - Vec2.x ) ^2 + ( InVec2.y - Vec2.y ) ^2 ) ^ 0.5 <= Radius
return InRadius
end
-- Test if a Vec3 is in the sphere of another Vec3
function UTILS.IsInSphere( InVec3, Vec3, Radius )
local InSphere = ( ( InVec3.x - Vec3.x ) ^2 + ( InVec3.y - Vec3.y ) ^2 + ( InVec3.z - Vec3.z ) ^2 ) ^ 0.5 <= Radius
return InSphere
end
-- Beaufort scale: returns Beaufort number and wind description as a function of wind speed in m/s.
function UTILS.BeaufortScale(speed)
local bn=nil
local bd=nil
if speed<0.51 then
bn=0
bd="Calm"
elseif speed<2.06 then
bn=1
bd="Light Air"
elseif speed<3.60 then
bn=2
bd="Light Breeze"
elseif speed<5.66 then
bn=3
bd="Gentle Breeze"
elseif speed<8.23 then
bn=4
bd="Moderate Breeze"
elseif speed<11.32 then
bn=5
bd="Fresh Breeze"
elseif speed<14.40 then
bn=6
bd="Strong Breeze"
elseif speed<17.49 then
bn=7
bd="Moderate Gale"
elseif speed<21.09 then
bn=8
bd="Fresh Gale"
elseif speed<24.69 then
bn=9
bd="Strong Gale"
elseif speed<28.81 then
bn=10
bd="Storm"
elseif speed<32.92 then
bn=11
bd="Violent Storm"
else
bn=12
bd="Hurricane"
end
return bn,bd
end