--- **Core** - Defines an extensive API to manage 3D points in the DCS World 3D simulation space. -- -- ## Features: -- -- * Provides a COORDINATE class, which allows to manage points in 3D space and perform various operations on it. -- * Provides a POINT\_VEC2 class, which is derived from COORDINATE, and allows to manage points in 3D space, but from a Lat/Lon and Altitude perspective. -- * Provides a POINT\_VEC3 class, which is derived from COORDINATE, and allows to manage points in 3D space, but from a X, Z and Y vector perspective. -- -- === -- -- ### Authors: -- -- * FlightControl (Design & Programming) -- -- ### Contributions: -- -- * funkyfranky -- * Applevangelist -- -- === -- -- @module Core.Point -- @image Core_Coordinate.JPG do -- COORDINATE --- Coordinate class -- @type COORDINATE -- @field #string ClassName Name of the class -- @field #number x Component of the 3D vector. -- @field #number y Component of the 3D vector. -- @field #number z Component of the 3D vector. -- @field #number Heading Heading in degrees. Needs to be set first. -- @field #number Velocity Velocity in meters per second. Needs to be set first. -- @extends Core.Base#BASE --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- # 1) Create a COORDINATE object. -- -- A new COORDINATE object can be created with 3 various methods: -- -- * @{#COORDINATE.New}(): from a 3D point. -- * @{#COORDINATE.NewFromVec2}(): from a @{DCS#Vec2} and possible altitude. -- * @{#COORDINATE.NewFromVec3}(): from a @{DCS#Vec3}. -- -- -- # 2) Smoke, flare, explode, illuminate at the coordinate. -- -- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods: -- -- ## 2.1) Smoke -- -- * @{#COORDINATE.Smoke}(): To smoke the point in a certain color. -- * @{#COORDINATE.SmokeBlue}(): To smoke the point in blue. -- * @{#COORDINATE.SmokeRed}(): To smoke the point in red. -- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange. -- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white. -- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green. -- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke. -- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke. -- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on. -- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off. -- -- ## 2.2) Flare -- -- * @{#COORDINATE.Flare}(): To flare the point in a certain color. -- * @{#COORDINATE.FlareRed}(): To flare the point in red. -- * @{#COORDINATE.FlareYellow}(): To flare the point in yellow. -- * @{#COORDINATE.FlareWhite}(): To flare the point in white. -- * @{#COORDINATE.FlareGreen}(): To flare the point in green. -- -- ## 2.3) Explode -- -- * @{#COORDINATE.Explosion}(): To explode the point with a certain intensity. -- -- ## 2.4) Illuminate -- -- * @{#COORDINATE.IlluminationBomb}(): To illuminate the point. -- -- -- # 3) Create markings on the map. -- -- Place markers (text boxes with clarifications for briefings, target locations or any other reference point) -- on the map for all players, coalitions or specific groups: -- -- * @{#COORDINATE.MarkToAll}(): Place a mark to all players. -- * @{#COORDINATE.MarkToCoalition}(): Place a mark to a coalition. -- * @{#COORDINATE.MarkToCoalitionRed}(): Place a mark to the red coalition. -- * @{#COORDINATE.MarkToCoalitionBlue}(): Place a mark to the blue coalition. -- * @{#COORDINATE.MarkToGroup}(): Place a mark to a group (needs to have a client in it or a CA group (CA group is bugged)). -- * @{#COORDINATE.RemoveMark}(): Removes a mark from the map. -- -- # 4) Coordinate calculation methods. -- -- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method: -- -- ## 4.1) Get the distance between 2 points. -- -- * @{#COORDINATE.Get3DDistance}(): Obtain the distance from the current 3D point to the provided 3D point in 3D space. -- * @{#COORDINATE.Get2DDistance}(): Obtain the distance from the current 3D point to the provided 3D point in 2D space. -- -- ## 4.2) Get the angle. -- -- * @{#COORDINATE.GetAngleDegrees}(): Obtain the angle in degrees from the current 3D point with the provided 3D direction vector. -- * @{#COORDINATE.GetAngleRadians}(): Obtain the angle in radians from the current 3D point with the provided 3D direction vector. -- * @{#COORDINATE.GetDirectionVec3}(): Obtain the 3D direction vector from the current 3D point to the provided 3D point. -- -- ## 4.3) Coordinate translation. -- -- * @{#COORDINATE.Translate}(): Translate the current 3D point towards an other 3D point using the given Distance and Angle. -- -- ## 4.4) Get the North correction of the current location. -- -- * @{#COORDINATE.GetNorthCorrectionRadians}(): Obtains the north correction at the current 3D point. -- -- ## 4.5) Point Randomization -- -- Various methods exist to calculate random locations around a given 3D point. -- -- * @{#COORDINATE.GetRandomVec2InRadius}(): Provides a random 2D vector around the current 3D point, in the given inner to outer band. -- * @{#COORDINATE.GetRandomVec3InRadius}(): Provides a random 3D vector around the current 3D point, in the given inner to outer band. -- -- ## 4.6) LOS between coordinates. -- -- Calculate if the coordinate has Line of Sight (LOS) with the other given coordinate. -- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibilty in a straight continuous line. -- The method @{#COORDINATE.IsLOS}() returns if the two coordinates have LOS. -- -- ## 4.7) Check the coordinate position. -- -- Various methods are available that allow to check if a coordinate is: -- -- * @{#COORDINATE.IsInRadius}(): in a give radius. -- * @{#COORDINATE.IsInSphere}(): is in a given sphere. -- * @{#COORDINATE.IsAtCoordinate2D}(): is in a given coordinate within a specific precision. -- -- -- -- # 5) Measure the simulation environment at the coordinate. -- -- ## 5.1) Weather specific. -- -- Within the DCS simulator, a coordinate has specific environmental properties, like wind, temperature, humidity etc. -- -- * @{#COORDINATE.GetWind}(): Retrieve the wind at the specific coordinate within the DCS simulator. -- * @{#COORDINATE.GetTemperature}(): Retrieve the temperature at the specific height within the DCS simulator. -- * @{#COORDINATE.GetPressure}(): Retrieve the pressure at the specific height within the DCS simulator. -- -- ## 5.2) Surface specific. -- -- Within the DCS simulator, the surface can have various objects placed at the coordinate, and the surface height will vary. -- -- * @{#COORDINATE.GetLandHeight}(): Retrieve the height of the surface (on the ground) within the DCS simulator. -- * @{#COORDINATE.GetSurfaceType}(): Retrieve the surface type (on the ground) within the DCS simulator. -- -- # 6) Create waypoints for routes. -- -- A COORDINATE can prepare waypoints for Ground and Air groups to be embedded into a Route. -- -- * @{#COORDINATE.WaypointAir}(): Build an air route point. -- * @{#COORDINATE.WaypointGround}(): Build a ground route point. -- * @{#COORDINATE.WaypointNaval}(): Build a naval route point. -- -- Route points can be used in the Route methods of the @{Wrapper.Group#GROUP} class. -- -- ## 7) Manage the roads. -- -- Important for ground vehicle transportation and movement, the method @{#COORDINATE.GetClosestPointToRoad}() will calculate -- the closest point on the nearest road. -- -- 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. -- -- ## 8) Metric or imperial system -- -- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles. -- * @{#COORDINATE.SetMetric}(): Sets the 3D point to Metric or Nautical Miles. -- -- -- ## 9) Coordinate text generation -- -- * @{#COORDINATE.ToStringBR}(): Generates a Bearing & Range text in the format of DDD for DI where DDD is degrees and DI is distance. -- * @{#COORDINATE.ToStringBRA}(): Generates a Bearing, Range & Altitude text. -- * @{#COORDINATE.ToStringBRAANATO}(): Generates a Generates a Bearing, Range, Aspect & Altitude text in NATOPS. -- * @{#COORDINATE.ToStringLL}(): Generates a Latitude & Longitude text. -- * @{#COORDINATE.ToStringLLDMS}(): Generates a Lat, Lon, Degree, Minute, Second text. -- * @{#COORDINATE.ToStringLLDDM}(): Generates a Lat, Lon, Degree, decimal Minute text. -- * @{#COORDINATE.ToStringMGRS}(): Generates a MGRS grid coordinate text. -- -- ## 10) Drawings on F10 map -- -- * @{#COORDINATE.CircleToAll}(): Draw a circle on the F10 map. -- * @{#COORDINATE.LineToAll}(): Draw a line on the F10 map. -- * @{#COORDINATE.RectToAll}(): Draw a rectangle on the F10 map. -- * @{#COORDINATE.QuadToAll}(): Draw a shape with four points on the F10 map. -- * @{#COORDINATE.TextToAll}(): Write some text on the F10 map. -- * @{#COORDINATE.ArrowToAll}(): Draw an arrow on the F10 map. -- -- @field #COORDINATE COORDINATE = { ClassName = "COORDINATE", } --- Waypoint altitude types. -- @type COORDINATE.WaypointAltType -- @field #string BARO Barometric altitude. -- @field #string RADIO Radio altitude. COORDINATE.WaypointAltType = { BARO = "BARO", RADIO = "RADIO", } --- Waypoint actions. -- @type COORDINATE.WaypointAction -- @field #string TurningPoint Turning point. -- @field #string FlyoverPoint Fly over point. -- @field #string FromParkingArea From parking area. -- @field #string FromParkingAreaHot From parking area hot. -- @field #string FromGroundAreaHot From ground area hot. -- @field #string FromGroundArea From ground area. -- @field #string FromRunway From runway. -- @field #string Landing Landing. -- @field #string LandingReFuAr Landing and refuel and rearm. COORDINATE.WaypointAction = { TurningPoint = "Turning Point", FlyoverPoint = "Fly Over Point", FromParkingArea = "From Parking Area", FromParkingAreaHot = "From Parking Area Hot", FromGroundAreaHot = "From Ground Area Hot", FromGroundArea = "From Ground Area", FromRunway = "From Runway", Landing = "Landing", LandingReFuAr = "LandingReFuAr", } --- Waypoint types. -- @type COORDINATE.WaypointType -- @field #string TakeOffParking Take of parking. -- @field #string TakeOffParkingHot Take of parking hot. -- @field #string TakeOff Take off parking hot. -- @field #string TakeOffGroundHot Take of from ground hot. -- @field #string TurningPoint Turning point. -- @field #string Land Landing point. -- @field #string LandingReFuAr Landing and refuel and rearm. COORDINATE.WaypointType = { TakeOffParking = "TakeOffParking", TakeOffParkingHot = "TakeOffParkingHot", TakeOff = "TakeOffParkingHot", TakeOffGroundHot = "TakeOffGroundHot", TakeOffGround = "TakeOffGround", TurningPoint = "Turning Point", Land = "Land", LandingReFuAr = "LandingReFuAr", } --- COORDINATE constructor. -- @param #COORDINATE self -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to up. -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the right. -- @return #COORDINATE self function COORDINATE:New( x, y, z ) local self=BASE:Inherit(self, BASE:New()) -- #COORDINATE self.x = x self.y = y self.z = z return self end --- COORDINATE constructor. -- @param #COORDINATE self -- @param #COORDINATE Coordinate. -- @return #COORDINATE self function COORDINATE:NewFromCoordinate( Coordinate ) local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE self.x = Coordinate.x self.y = Coordinate.y self.z = Coordinate.z return self end --- Create a new COORDINATE object from Vec2 coordinates. -- @param #COORDINATE self -- @param DCS#Vec2 Vec2 The Vec2 point. -- @param DCS#Distance LandHeightAdd (Optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. -- @return #COORDINATE self function COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) local LandHeight = land.getHeight( Vec2 ) LandHeightAdd = LandHeightAdd or 0 LandHeight = LandHeight + LandHeightAdd local self = self:New( Vec2.x, LandHeight, Vec2.y ) -- #COORDINATE return self end --- Create a new COORDINATE object from Vec3 coordinates. -- @param #COORDINATE self -- @param DCS#Vec3 Vec3 The Vec3 point. -- @return #COORDINATE self function COORDINATE:NewFromVec3( Vec3 ) local self = self:New( Vec3.x, Vec3.y, Vec3.z ) -- #COORDINATE self:F2( self ) return self end --- Create a new COORDINATE object from a waypoint. This uses the components -- -- * `waypoint.x` -- * `waypoint.alt` -- * `waypoint.y` -- -- @param #COORDINATE self -- @param DCS#Waypoint Waypoint The waypoint. -- @return #COORDINATE self function COORDINATE:NewFromWaypoint(Waypoint) local self=self:New(Waypoint.x, Waypoint.alt, Waypoint.y) -- #COORDINATE return self end --- Return the coordinates itself. Sounds stupid but can be useful for compatibility. -- @param #COORDINATE self -- @return #COORDINATE self function COORDINATE:GetCoordinate() return self end --- Return the coordinates of the COORDINATE in Vec3 format. -- @param #COORDINATE self -- @return DCS#Vec3 The Vec3 format coordinate. function COORDINATE:GetVec3() return { x = self.x, y = self.y, z = self.z } end --- Return the coordinates of the COORDINATE in Vec2 format. -- @param #COORDINATE self -- @return DCS#Vec2 The Vec2 format coordinate. function COORDINATE:GetVec2() return { x = self.x, y = self.z } end --- Update x,y,z coordinates from a given 3D vector. -- @param #COORDINATE self -- @param DCS#Vec3 Vec3 The 3D vector with x,y,z components. -- @return #COORDINATE The modified COORDINATE itself. function COORDINATE:UpdateFromVec3(Vec3) self.x=Vec3.x self.y=Vec3.y self.z=Vec3.z return self end --- Update x,y,z coordinates from another given COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE Coordinate The coordinate with the new x,y,z positions. -- @return #COORDINATE The modified COORDINATE itself. function COORDINATE:UpdateFromCoordinate(Coordinate) self.x=Coordinate.x self.y=Coordinate.y self.z=Coordinate.z return self end --- Update x and z coordinates from a given 2D vector. -- @param #COORDINATE self -- @param DCS#Vec2 Vec2 The 2D vector with x,y components. x is overwriting COORDINATE.x while y is overwriting COORDINATE.z. -- @return #COORDINATE The modified COORDINATE itself. function COORDINATE:UpdateFromVec2(Vec2) self.x=Vec2.x self.z=Vec2.y return self end --- Returns the magnetic declination at the given coordinate. -- NOTE that this needs `require` to be available so you need to desanitize the `MissionScripting.lua` file in your DCS/Scrips folder. -- If `require` is not available, a constant value for the whole map. -- @param #COORDINATE self -- @param #number Month (Optional) The month at which the declination is calculated. Default is the mission month. -- @param #number Year (Optional) The year at which the declination is calculated. Default is the mission year. -- @return #number Magnetic declination in degrees. function COORDINATE:GetMagneticDeclination(Month, Year) local decl=UTILS.GetMagneticDeclination() if require then local magvar = require('magvar') if magvar then local date, year, month, day=UTILS.GetDCSMissionDate() magvar.init(Month or month, Year or year) local lat, lon=self:GetLLDDM() decl=magvar.get_mag_decl(lat, lon) if decl then decl=math.deg(decl) end end else self:T("The require package is not available. Using constant value for magnetic declination") end return decl end --- Returns the coordinate from the latitude and longitude given in decimal degrees. -- @param #COORDINATE self -- @param #number latitude Latitude in decimal degrees. -- @param #number longitude Longitude in decimal degrees. -- @param #number altitude (Optional) Altitude in meters. Default is the land height at the coordinate. -- @return #COORDINATE function COORDINATE:NewFromLLDD( latitude, longitude, altitude) -- Returns a point from latitude and longitude in the vec3 format. local vec3=coord.LLtoLO(latitude, longitude) -- Convert vec3 to coordinate object. local _coord=self:NewFromVec3(vec3) -- Adjust height if altitude==nil then _coord.y=self:GetLandHeight() else _coord.y=altitude end return _coord end --- Returns if the 2 coordinates are at the same 2D position. -- @param #COORDINATE self -- @param #COORDINATE Coordinate -- @param #number Precision -- @return #boolean true if at the same position. function COORDINATE:IsAtCoordinate2D( Coordinate, Precision ) self:F( { Coordinate = Coordinate:GetVec2() } ) self:F( { self = self:GetVec2() } ) local x = Coordinate.x local z = Coordinate.z return x - Precision <= self.x and x + Precision >= self.x and z - Precision <= self.z and z + Precision >= self.z end --- Scan/find objects (units, statics, scenery) within a certain radius around the coordinate using the world.searchObjects() DCS API function. -- @param #COORDINATE self -- @param #number radius (Optional) Scan radius in meters. Default 100 m. -- @param #boolean scanunits (Optional) If true scan for units. Default true. -- @param #boolean scanstatics (Optional) If true scan for static objects. Default true. -- @param #boolean scanscenery (Optional) If true scan for scenery objects. Default false. -- @return #boolean True if units were found. -- @return #boolean True if statics were found. -- @return #boolean True if scenery objects were found. -- @return #table Table of MOOSE @{Wrapper.Unit#UNIT} objects found. -- @return #table Table of DCS static objects found. -- @return #table Table of DCS scenery objects found. function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery) self:F(string.format("Scanning in radius %.1f m.", radius or 100)) local SphereSearch = { id = world.VolumeType.SPHERE, params = { point = self:GetVec3(), radius = radius, } } -- Defaults radius=radius or 100 if scanunits==nil then scanunits=true end if scanstatics==nil then scanstatics=true end if scanscenery==nil then scanscenery=false end --{Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY} local scanobjects={} if scanunits then table.insert(scanobjects, Object.Category.UNIT) end if scanstatics then table.insert(scanobjects, Object.Category.STATIC) end if scanscenery then table.insert(scanobjects, Object.Category.SCENERY) end -- Found stuff. local Units = {} local Statics = {} local Scenery = {} local gotstatics=false local gotunits=false local gotscenery=false local function EvaluateZone(ZoneObject) if ZoneObject then -- Get category of scanned object. local ObjectCategory = Object.getCategory(ZoneObject) -- Check for unit or static objects if ObjectCategory==Object.Category.UNIT and ZoneObject:isExist() then table.insert(Units, UNIT:Find(ZoneObject)) gotunits=true elseif ObjectCategory==Object.Category.STATIC and ZoneObject:isExist() then table.insert(Statics, ZoneObject) gotstatics=true elseif ObjectCategory==Object.Category.SCENERY then table.insert(Scenery, ZoneObject) gotscenery=true end end return true end -- Search the world. world.searchObjects(scanobjects, SphereSearch, EvaluateZone) for _,unit in pairs(Units) do self:T(string.format("Scan found unit %s", unit:GetName())) end for _,static in pairs(Statics) do self:T(string.format("Scan found static %s", static:getName())) _DATABASE:AddStatic(static:getName()) end for _,scenery in pairs(Scenery) do self:T(string.format("Scan found scenery %s typename=%s", scenery:getName(), scenery:getTypeName())) --SCENERY:Register(scenery:getName(), scenery) end return gotunits, gotstatics, gotscenery, Units, Statics, Scenery end --- Scan/find UNITS within a certain radius around the coordinate using the world.searchObjects() DCS API function. -- @param #COORDINATE self -- @param #number radius (Optional) Scan radius in meters. Default 100 m. -- @return Core.Set#SET_UNIT Set of units. function COORDINATE:ScanUnits(radius) local _,_,_,units=self:ScanObjects(radius, true, false, false) local set=SET_UNIT:New() for _,unit in pairs(units) do set:AddUnit(unit) end return set end --- Scan/find STATICS within a certain radius around the coordinate using the world.searchObjects() DCS API function. -- @param #COORDINATE self -- @param #number radius (Optional) Scan radius in meters. Default 100 m. -- @return Core.Set#SET_UNIT Set of units. function COORDINATE:ScanStatics(radius) local _,_,_,_,statics=self:ScanObjects(radius, false, true, false) local set=SET_STATIC:New() for _,stat in pairs(statics) do set:AddStatic(STATIC:Find(stat)) end return set end --- Find the closest static to the COORDINATE within a certain radius. -- @param #COORDINATE self -- @param #number radius Scan radius in meters. Default 100 m. -- @return Wrapper.Static#STATIC The closest static or #nil if no unit is inside the given radius. function COORDINATE:FindClosestStatic(radius) local units=self:ScanStatics(radius) local umin=nil --Wrapper.Unit#UNIT local dmin=math.huge for _,_unit in pairs(units.Set) do local unit=_unit --Wrapper.Static#STATIC local coordinate=unit:GetCoordinate() local d=self:Get2DDistance(coordinate) if d1 then local norm=UTILS.VecNorm(vec) f=Fraction/norm end -- Scale the vector. vec.x=f*vec.x vec.y=f*vec.y vec.z=f*vec.z -- Move the vector to start at the end of A. vec=UTILS.VecAdd(self, vec) -- Create a new coordiante object. local coord=COORDINATE:New(vec.x,vec.y,vec.z) return coord end --- Return the 2D distance in meters between the target COORDINATE and the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3. -- @return DCS#Distance Distance The distance in meters. function COORDINATE:Get2DDistance(TargetCoordinate) if not TargetCoordinate then return 1000000 end --local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z} local a = self:GetVec2() if not TargetCoordinate.ClassName then TargetCoordinate=COORDINATE:NewFromVec3(TargetCoordinate) end local b = TargetCoordinate:GetVec2() local norm=UTILS.VecDist2D(a,b) return norm end --- Returns the temperature in Degrees Celsius. -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. -- @return Temperature in Degrees Celsius. function COORDINATE:GetTemperature(height) self:F2(height) local y=height or self.y local point={x=self.x, y=height or self.y, z=self.z} -- get temperature [K] and pressure [Pa] at point local T,P=atmosphere.getTemperatureAndPressure(point) -- Return Temperature in Deg C return T-273.15 end --- Returns a text of the temperature according the measurement system @{Core.Settings}. -- The text will reflect the temperature like this: -- -- - For Russian and European aircraft using the metric system - Degrees Celcius (°C) -- - For American aircraft we link to the imperial system - Degrees Fahrenheit (°F) -- -- A text containing a pressure will look like this: -- -- - `Temperature: %n.d °C` -- - `Temperature: %n.d °F` -- -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. -- @return #string Temperature according the measurement system @{Core.Settings}. function COORDINATE:GetTemperatureText( height, Settings ) local DegreesCelcius = self:GetTemperature( height ) local Settings = Settings or _SETTINGS if DegreesCelcius then if Settings:IsMetric() then return string.format( " %-2.2f °C", DegreesCelcius ) else return string.format( " %-2.2f °F", UTILS.CelsiusToFahrenheit( DegreesCelcius ) ) end else return " no temperature" end return nil end --- Returns the pressure in hPa. -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH. -- @return Pressure in hPa. function COORDINATE:GetPressure(height) local point={x=self.x, y=height or self.y, z=self.z} -- get temperature [K] and pressure [Pa] at point local T,P=atmosphere.getTemperatureAndPressure(point) -- Return Pressure in hPa. return P/100 end --- Returns a text of the pressure according the measurement system @{Core.Settings}. -- The text will contain always the pressure in hPa and: -- -- - For Russian and European aircraft using the metric system - hPa and mmHg -- - For American and European aircraft we link to the imperial system - hPa and inHg -- -- A text containing a pressure will look like this: -- -- - `QFE: x hPa (y mmHg)` -- - `QFE: x hPa (y inHg)` -- -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH. -- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Core.Settings}. function COORDINATE:GetPressureText( height, Settings ) local Pressure_hPa = self:GetPressure( height ) local Pressure_mmHg = Pressure_hPa * 0.7500615613030 local Pressure_inHg = Pressure_hPa * 0.0295299830714 local Settings = Settings or _SETTINGS if Pressure_hPa then if Settings:IsMetric() then return string.format( " %4.1f hPa (%3.1f mmHg)", Pressure_hPa, Pressure_mmHg ) else return string.format( " %4.1f hPa (%3.2f inHg)", Pressure_hPa, Pressure_inHg ) end else return " no pressure" end return nil end --- Returns the heading from this to another coordinate. -- @param #COORDINATE self -- @param #COORDINATE ToCoordinate -- @return #number Heading in degrees. function COORDINATE:HeadingTo(ToCoordinate) local dz=ToCoordinate.z-self.z local dx=ToCoordinate.x-self.x local heading=math.deg(math.atan2(dz, dx)) if heading < 0 then heading = 360 + heading end return heading end --- Returns the 3D wind direction vector. Note that vector points into the direction the wind in blowing to. -- @param #COORDINATE self -- @param #number height (Optional) parameter specifying the height ASL in meters. The minimum height will be always be the land height since the wind is zero below the ground. -- @param #boolean turbulence (Optional) If `true`, include turbulence. -- @return DCS#Vec3 Wind 3D vector. Components in m/s. function COORDINATE:GetWindVec3(height, turbulence) -- We at 0.1 meters to be sure to be above ground since wind is zero below ground level. local landheight=self:GetLandHeight()+0.1 local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z} -- Get wind velocity vector. local wind = nil --DCS#Vec3 if turbulence then wind = atmosphere.getWindWithTurbulence(point) else wind = atmosphere.getWind(point) end return wind end --- Returns the wind direction (from) and strength. -- @param #COORDINATE self -- @param #number height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. -- @param #boolean turbulence If `true`, include turbulence. If `false` or `nil`, wind without turbulence. -- @return #number Direction the wind is blowing from in degrees. -- @return #number Wind strength in m/s. function COORDINATE:GetWind(height, turbulence) -- Get wind velocity vector local wind = self:GetWindVec3(height, turbulence) -- Calculate the direction of the vector. local direction=UTILS.VecHdg(wind) -- Invert "to" direction to "from" direction. if direction > 180 then direction = direction-180 else direction = direction+180 end -- Wind strength in m/s. local strength=UTILS.VecNorm(wind) -- math.sqrt((wind.x)^2+(wind.z)^2) -- Return wind direction and strength. return direction, strength end --- Returns the wind direction (from) and strength. -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. -- @return Direction the wind is blowing from in degrees. function COORDINATE:GetWindWithTurbulenceVec3(height) -- AGL height if local landheight=self:GetLandHeight()+0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level. -- Point at which the wind is evaluated. local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z} -- Get wind velocity vector including turbulences. local vec3 = atmosphere.getWindWithTurbulence(point) return vec3 end --- Return the x coordinate of the COORDINATE. -- @param #COORDINATE self -- @return #number The x coordinate. function COORDINATE:GetX() return self.x end --- Return the y coordinate of the COORDINATE. -- @param #COORDINATE self -- @return #number The y coordinate. function COORDINATE:GetY() if self:IsInstanceOf("POINT_VEC2") then return self.z end return self.y end --- Return the z coordinate of the COORDINATE. -- @param #COORDINATE self -- @return #number The z coordinate. function COORDINATE:GetZ() return self.z end --- Set the x coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number x The x coordinate. -- @return #COORDINATE function COORDINATE:SetX( x ) self.x = x return self end --- Set the y coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number y The y coordinate. -- @return #COORDINATE function COORDINATE:SetY( y ) if self:IsInstanceOf("POINT_VEC2") then self.z = y else self.y = y end return self end --- Set the z coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number z The z coordinate. -- @return #COORDINATE function COORDINATE:SetZ( z ) self.z = z return self end --- Add to the x coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number x The x coordinate value to add to the current x coordinate. -- @return #COORDINATE function COORDINATE:AddX( x ) self.x = self.x + x return self end --- Return Return the Lat(itude) coordinate of the COORDINATE (ie: (parent)COORDINATE.x). -- @param #COORDINATE self -- @return #number The x coordinate. function COORDINATE:GetLat() return self.x end --- Set the Lat(itude) coordinate of the COORDINATE (ie: COORDINATE.x). -- @param #COORDINATE self -- @param #number x The x coordinate. -- @return #COORDINATE function COORDINATE:SetLat( x ) self.x = x return self end --- Return the Lon(gitude) coordinate of the COORDINATE (ie: (parent)COORDINATE.z). -- @param #COORDINATE self -- @return #number The y coordinate. function COORDINATE:GetLon() return self.z end --- Set the Lon(gitude) coordinate of the COORDINATE (ie: COORDINATE.z). -- @param #COORDINATE self -- @param #number y The y coordinate. -- @return #COORDINATE function COORDINATE:SetLon( z ) self.z = z return self end --- Return the altitude (height) of the land at the COORDINATE. -- @param #COORDINATE self -- @return #number The land altitude. function COORDINATE:GetAlt() return self.y ~= 0 or land.getHeight( { x = self.x, y = self.z } ) end --- Set the altitude of the COORDINATE. -- @param #COORDINATE self -- @param #number Altitude The land altitude. If nothing (nil) is given, then the current land altitude is set. -- @return #COORDINATE function COORDINATE:SetAlt( Altitude ) self.y = Altitude or land.getHeight( { x = self.x, y = self.z } ) return self end --- Add to the current land height an altitude. -- @param #COORDINATE self -- @param #number Altitude The Altitude to add. If nothing (nil) is given, then the current land altitude is set. -- @return #COORDINATE function COORDINATE:AddAlt( Altitude ) self.y = land.getHeight( { x = self.x, y = self.z } ) + Altitude or 0 return self end --- Return a random COORDINATE within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self -- @param DCS#Distance OuterRadius -- @param DCS#Distance InnerRadius -- @return #COORDINATE function COORDINATE:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) self:F2( { OuterRadius, InnerRadius } ) return COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) end --- Add to the y coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number y The y coordinate value to add to the current y coordinate. -- @return #COORDINATE function COORDINATE:AddY( y ) if self:IsInstanceOf("POINT_VEC2") then return self:AddZ(y) else self.y = self.y + y end return self end --- Add to the z coordinate of the COORDINATE. -- @param #COORDINATE self -- @param #number z The z coordinate value to add to the current z coordinate. -- @return #COORDINATE function COORDINATE:AddZ( z ) self.z = self.z +z return self end --- Returns a text documenting the wind direction (from) and strength according the measurement system @{Core.Settings}. -- The text will reflect the wind like this: -- -- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps). -- - For American aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps). -- -- A text containing a pressure will look like this: -- -- - `Wind: %n ° at n.d mps` -- - `Wind: %n ° at n.d kps` -- -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. -- @return #string Wind direction and strength according the measurement system @{Core.Settings}. function COORDINATE:GetWindText( height, Settings ) local Direction, Strength = self:GetWind( height ) local Settings = Settings or _SETTINGS if Direction and Strength then if Settings:IsMetric() then return string.format( " %d ° at %3.2f mps", Direction, UTILS.MpsToKmph( Strength ) ) else return string.format( " %d ° at %3.2f kps", Direction, UTILS.MpsToKnots( Strength ) ) end else return " no wind" end return nil end --- Return the 3D distance in meters between the target COORDINATE and the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3. -- @return DCS#Distance Distance The distance in meters. function COORDINATE:Get3DDistance( TargetCoordinate ) --local TargetVec3 = TargetCoordinate:GetVec3() local TargetVec3 = {x=TargetCoordinate.x, y=TargetCoordinate.y, z=TargetCoordinate.z} local SourceVec3 = self:GetVec3() --local dist=( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 local dist=UTILS.VecDist3D(TargetVec3, SourceVec3) return dist end --- Provides a bearing text in degrees. -- @param #COORDINATE self -- @param #number AngleRadians The angle in randians. -- @param #number Precision The precision. -- @param Core.Settings#SETTINGS Settings -- @param #boolean MagVar If true, include magentic degrees -- @return #string The bearing text in degrees. function COORDINATE:GetBearingText( AngleRadians, Precision, Settings, MagVar ) local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local AngleDegrees = UTILS.Round( UTILS.ToDegree( AngleRadians ), Precision ) local s = string.format( '%03d°', AngleDegrees ) if MagVar then local variation = self:GetMagneticDeclination() or 0 local AngleMagnetic = AngleDegrees - variation if AngleMagnetic < 0 then AngleMagnetic = 360-AngleMagnetic end s = string.format( '%03d°M|%03d°', AngleMagnetic,AngleDegrees ) end return s end --- Provides a distance text expressed in the units of measurement. -- @param #COORDINATE self -- @param #number Distance The distance in meters. -- @param Core.Settings#SETTINGS Settings -- @param #string Language (optional) "EN" or "RU" -- @param #number Precision (optional) round to this many decimal places -- @return #string The distance text expressed in the units of measurement. function COORDINATE:GetDistanceText( Distance, Settings, Language, Precision ) local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN" Language = string.lower(Language) local Precision = Precision or 0 local DistanceText if Settings:IsMetric() then if Language == "en" then DistanceText = " for " .. UTILS.Round( Distance / 1000, Precision ) .. " km" elseif Language == "ru" then DistanceText = " за " .. UTILS.Round( Distance / 1000, Precision ) .. " километров" end else if Language == "en" then DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " miles" elseif Language == "ru" then DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " миль" end end return DistanceText end --- Return the altitude text of the COORDINATE. -- @param #COORDINATE self -- @return #string Altitude text. function COORDINATE:GetAltitudeText( Settings, Language ) local Altitude = self.y local Settings = Settings or _SETTINGS local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN" Language = string.lower(Language) if Altitude ~= 0 then if Settings:IsMetric() then if Language == "en" then return " at " .. UTILS.Round( self.y, -3 ) .. " meters" elseif Language == "ru" then return " в " .. UTILS.Round( self.y, -3 ) .. " метры" end else if Language == "en" then return " at " .. UTILS.Round( UTILS.MetersToFeet( self.y ), -3 ) .. " feet" elseif Language == "ru" then return " в " .. UTILS.Round( self.y, -3 ) .. " ноги" end end else return "" end end --- Return the velocity text of the COORDINATE. -- @param #COORDINATE self -- @return #string Velocity text. function COORDINATE:GetVelocityText( Settings ) local Velocity = self:GetVelocity() local Settings = Settings or _SETTINGS if Velocity then if Settings:IsMetric() then return string.format( " moving at %d km/h", UTILS.MpsToKmph( Velocity ) ) else return string.format( " moving at %d mi/h", UTILS.MpsToKmph( Velocity ) / 1.852 ) end else return " stationary" end end --- Return the heading text of the COORDINATE. -- @param #COORDINATE self -- @return #string Heading text. function COORDINATE:GetHeadingText( Settings ) local Heading = self:GetHeading() if Heading then return string.format( " bearing %3d°", Heading ) else return " bearing unknown" end end --- Provides a Bearing / Range string -- @param #COORDINATE self -- @param #number AngleRadians The angle in randians -- @param #number Distance The distance -- @param Core.Settings#SETTINGS Settings -- @param #string Language (Optional) Language "en" or "ru" -- @param #boolean MagVar If true, also state angle in magnetic -- @param #number Precision Rounding precision, defaults to 0 -- @return #string The BR Text function COORDINATE:GetBRText( AngleRadians, Distance, Settings, Language, MagVar, Precision ) local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS Precision = Precision or 0 local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar ) local DistanceText = self:GetDistanceText( Distance, Settings, Language, Precision ) local BRText = BearingText .. DistanceText return BRText end --- Provides a Bearing / Range / Altitude string -- @param #COORDINATE self -- @param #number AngleRadians The angle in randians -- @param #number Distance The distance -- @param Core.Settings#SETTINGS Settings -- @param #string Language (Optional) Language "en" or "ru" -- @param #boolean MagVar If true, also state angle in magnetic -- @return #string The BRA Text function COORDINATE:GetBRAText( AngleRadians, Distance, Settings, Language, MagVar ) local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar ) local DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 ) local AltitudeText = self:GetAltitudeText( Settings, Language ) local BRAText = BearingText .. DistanceText .. AltitudeText -- When the POINT is a VEC2, there will be no altitude shown. return BRAText end --- Set altitude. -- @param #COORDINATE self -- @param #number altitude New altitude in meters. -- @param #boolean asl Altitude above sea level. Default is above ground level. -- @return #COORDINATE The COORDINATE with adjusted altitude. function COORDINATE:SetAltitude(altitude, asl) local alt=altitude if asl then alt=altitude else alt=self:GetLandHeight()+altitude end self.y=alt return self end --- Set altitude to be at land height (i.e. on the ground!) -- @param #COORDINATE self function COORDINATE:SetAtLandheight() local alt=self:GetLandHeight() self.y=alt return self end --- Build an air type route point. -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param #COORDINATE.WaypointType Type The route point type. -- @param #COORDINATE.WaypointAction Action The route point action. -- @param DCS#Speed Speed Airspeed in km/h. Default is 500 km/h. -- @param #boolean SpeedLocked true means the speed is locked. -- @param Wrapper.Airbase#AIRBASE airbase The airbase for takeoff and landing points. -- @param #table DCSTasks A table of @{DCS#Task} items which are executed at the waypoint. -- @param #string description A text description of the waypoint, which will be shown on the F10 map. -- @param #number timeReFuAr Time in minutes the aircraft stays at the airport for ReFueling and ReArming. -- @return #table The route point. function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked, airbase, DCSTasks, description, timeReFuAr ) self:F2( { AltType, Type, Action, Speed, SpeedLocked } ) -- Set alttype or "RADIO" which is AGL. AltType=AltType or "RADIO" -- Speedlocked by default if SpeedLocked==nil then SpeedLocked=true end -- Speed or default 500 km/h. Speed=Speed or 500 -- Waypoint array. local RoutePoint = {} -- Coordinates. RoutePoint.x = self.x RoutePoint.y = self.z -- Altitude. RoutePoint.alt = self.y RoutePoint.alt_type = AltType -- Waypoint type. RoutePoint.type = Type or nil RoutePoint.action = Action or nil -- Speed. RoutePoint.speed = Speed/3.6 RoutePoint.speed_locked = SpeedLocked -- ETA. RoutePoint.ETA=0 RoutePoint.ETA_locked=false -- Waypoint description. RoutePoint.name=description -- Airbase parameters for takeoff and landing points. if airbase then local AirbaseID = airbase:GetID() local AirbaseCategory = airbase:GetAirbaseCategory() if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then RoutePoint.linkUnit = AirbaseID RoutePoint.helipadId = AirbaseID elseif AirbaseCategory == Airbase.Category.AIRDROME then RoutePoint.airdromeId = AirbaseID else self:E("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!") end end -- Time in minutes to stay at the airbase before resuming route. if Type==COORDINATE.WaypointType.LandingReFuAr then RoutePoint.timeReFuAr=timeReFuAr or 10 end -- Waypoint tasks. RoutePoint.task = {} RoutePoint.task.id = "ComboTask" RoutePoint.task.params = {} RoutePoint.task.params.tasks = DCSTasks or {} --RoutePoint.properties={} --RoutePoint.properties.addopt={} --RoutePoint.formation_template="" -- Debug. self:T({RoutePoint=RoutePoint}) -- Return waypoint. return RoutePoint end --- Build a Waypoint Air "Turning Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param DCS#Speed Speed Airspeed in km/h. -- @param #table DCSTasks (Optional) A table of @{DCS#Task} items which are executed at the waypoint. -- @param #string description (Optional) A text description of the waypoint, which will be shown on the F10 map. -- @return #table The route point. function COORDINATE:WaypointAirTurningPoint( AltType, Speed, DCSTasks, description ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true, nil, DCSTasks, description ) end --- Build a Waypoint Air "Fly Over Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, Speed ) end --- Build a Waypoint Air "Take Off Parking Hot". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParkingHot, COORDINATE.WaypointAction.FromParkingAreaHot, Speed ) end --- Build a Waypoint Air "Take Off Parking". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffParking( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, Speed ) end --- Build a Waypoint Air "Take Off Runway". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOff, COORDINATE.WaypointAction.FromRunway, Speed ) end --- Build a Waypoint Air "Landing". -- @param #COORDINATE self -- @param DCS#Speed Speed Airspeed in km/h. -- @param Wrapper.Airbase#AIRBASE airbase The airbase for takeoff and landing points. -- @param #table DCSTasks A table of @{DCS#Task} items which are executed at the waypoint. -- @param #string description A text description of the waypoint, which will be shown on the F10 map. -- @return #table The route point. -- @usage -- -- LandingZone = ZONE:New( "LandingZone" ) -- LandingCoord = LandingZone:GetCoordinate() -- LandingWaypoint = LandingCoord:WaypointAirLanding( 60 ) -- HeliGroup:Route( { LandWaypoint }, 1 ) -- Start landing the helicopter in one second. -- function COORDINATE:WaypointAirLanding( Speed, airbase, DCSTasks, description ) return self:WaypointAir(nil, COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, Speed, false, airbase, DCSTasks, description) end --- Build a Waypoint Air "LandingReFuAr". Mimics the aircraft ReFueling and ReArming. -- @param #COORDINATE self -- @param DCS#Speed Speed Airspeed in km/h. -- @param Wrapper.Airbase#AIRBASE airbase The airbase for takeoff and landing points. -- @param #number timeReFuAr Time in minutes, the aircraft stays at the airbase. Default 10 min. -- @param #table DCSTasks A table of @{DCS#Task} items which are executed at the waypoint. -- @param #string description A text description of the waypoint, which will be shown on the F10 map. -- @return #table The route point. function COORDINATE:WaypointAirLandingReFu( Speed, airbase, timeReFuAr, DCSTasks, description ) return self:WaypointAir(nil, COORDINATE.WaypointType.LandingReFuAr, COORDINATE.WaypointAction.LandingReFuAr, Speed, false, airbase, DCSTasks, description, timeReFuAr or 10) end --- Build an ground type route point. -- @param #COORDINATE self -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. -- @param #string Formation (Optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". -- @param #table DCSTasks (Optional) A table of DCS tasks that are executed at the waypoints. Mind the curly brackets {}! -- @return #table The route point. function COORDINATE:WaypointGround( Speed, Formation, DCSTasks ) self:F2( { Speed, Formation, DCSTasks } ) local RoutePoint = {} RoutePoint.x = self.x RoutePoint.y = self.z RoutePoint.alt = self:GetLandHeight()+1 RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO RoutePoint.type = "Turning Point" RoutePoint.action = Formation or "Off Road" RoutePoint.formation_template="" RoutePoint.ETA=0 RoutePoint.ETA_locked=false RoutePoint.speed = ( Speed or 20 ) / 3.6 RoutePoint.speed_locked = true RoutePoint.task = {} RoutePoint.task.id = "ComboTask" RoutePoint.task.params = {} RoutePoint.task.params.tasks = DCSTasks or {} return RoutePoint end --- Build route waypoint point for Naval units. -- @param #COORDINATE self -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. -- @param #string Depth (Optional) Dive depth in meters. Only for submarines. Default is COORDINATE.y component. -- @param #table DCSTasks (Optional) A table of DCS tasks that are executed at the waypoints. Mind the curly brackets {}! -- @return #table The route point. function COORDINATE:WaypointNaval( Speed, Depth, DCSTasks ) self:F2( { Speed, Depth, DCSTasks } ) local RoutePoint = {} RoutePoint.x = self.x RoutePoint.y = self.z RoutePoint.alt = Depth or self.y -- Depth is for submarines only. Ships should have alt=0. RoutePoint.alt_type = "BARO" RoutePoint.type = "Turning Point" RoutePoint.action = "Turning Point" RoutePoint.formation_template = "" RoutePoint.ETA=0 RoutePoint.ETA_locked=false RoutePoint.speed = ( Speed or 20 ) / 3.6 RoutePoint.speed_locked = true RoutePoint.task = {} RoutePoint.task.id = "ComboTask" RoutePoint.task.params = {} RoutePoint.task.params.tasks = DCSTasks or {} return RoutePoint end --- Gets the nearest airbase with respect to the current coordinates. -- @param #COORDINATE self -- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}. -- @param #number Coalition (Optional) Coalition of the airbase. -- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate. -- @return #number Distance to the closest airbase in meters. function COORDINATE:GetClosestAirbase(Category, Coalition) -- Get all airbases of the map. local airbases=AIRBASE.GetAllAirbases(Coalition) local closest=nil local distmin=nil -- Loop over all airbases. for _,_airbase in pairs(airbases) do local airbase=_airbase --Wrapper.Airbase#AIRBASE if airbase then local category=airbase:GetAirbaseCategory() if Category and Category==category or Category==nil then -- Distance to airbase. local dist=self:Get2DDistance(airbase:GetCoordinate()) if closest==nil then distmin=dist closest=airbase else if dist=2 then for i=1,#Path-1 do Way=Way+Path[i+1]:Get2DDistance(Path[i]) end else -- There are cases where no path on road can be found. return nil,nil,false end return Path, Way, GotPath end --- Gets the surface type at the coordinate. -- @param #COORDINATE self -- @return DCS#SurfaceType Surface type. function COORDINATE:GetSurfaceType() local vec2=self:GetVec2() local surface=land.getSurfaceType(vec2) return surface end --- Checks if the surface type is on land. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is land. function COORDINATE:IsSurfaceTypeLand() return self:GetSurfaceType()==land.SurfaceType.LAND end --- Checks if the surface type is land. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is land. function COORDINATE:IsSurfaceTypeLand() return self:GetSurfaceType()==land.SurfaceType.LAND end --- Checks if the surface type is road. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a road. function COORDINATE:IsSurfaceTypeRoad() return self:GetSurfaceType()==land.SurfaceType.ROAD end --- Checks if the surface type is runway. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a runway or taxi way. function COORDINATE:IsSurfaceTypeRunway() return self:GetSurfaceType()==land.SurfaceType.RUNWAY end --- Checks if the surface type is shallow water. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a shallow water. function COORDINATE:IsSurfaceTypeShallowWater() return self:GetSurfaceType()==land.SurfaceType.SHALLOW_WATER end --- Checks if the surface type is water. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a deep water. function COORDINATE:IsSurfaceTypeWater() return self:GetSurfaceType()==land.SurfaceType.WATER end --- Creates an explosion at the point of a certain intensity. -- @param #COORDINATE self -- @param #number ExplosionIntensity Intensity of the explosion in kg TNT. Default 100 kg. -- @param #number Delay (Optional) Delay before explosion is triggered in seconds. -- @return #COORDINATE self function COORDINATE:Explosion( ExplosionIntensity, Delay ) ExplosionIntensity=ExplosionIntensity or 100 if Delay and Delay>0 then self:ScheduleOnce(Delay, self.Explosion, self, ExplosionIntensity) else trigger.action.explosion(self:GetVec3(), ExplosionIntensity) end return self end --- Creates an illumination bomb at the point. -- @param #COORDINATE self -- @param #number Power Power of illumination bomb in Candela. Default 1000 cd. -- @param #number Delay (Optional) Delay before bomb is ignited in seconds. -- @return #COORDINATE self function COORDINATE:IlluminationBomb(Power, Delay) Power=Power or 1000 if Delay and Delay>0 then self:ScheduleOnce(Delay, self.IlluminationBomb, self, Power) else trigger.action.illuminationBomb(self:GetVec3(), Power) end return self end --- Create colored smoke the point. The smoke we last up to 5 min (DCS limitation) but you can optionally specify a shorter duration or stop it manually. -- @param #COORDINATE self -- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke. -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) -- @param #boolean Offset (Optional) If true, offset the smokle a bit. -- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random. -- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20. -- @return #COORDINATE self function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance) self:F2( { SmokeColor, Name, Duration, Delay, Offset } ) SmokeColor=SmokeColor or SMOKECOLOR.Green if Delay and Delay>0 then self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance) else -- Create a name which is used to stop the smoke manually self.firename = Name or "Smoke-"..math.random(1,100000) -- Create smoke if Offset or self.SmokeOffset then local Angle = Direction or self:GetSmokeOffsetDirection() local Distance = Distance or self:GetSmokeOffsetDistance() local newpos = self:Translate(Distance,Angle,true,false) local newvec3 = newpos:GetVec3() trigger.action.smoke( newvec3, SmokeColor, self.firename ) else trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) end -- Stop smoke if Duration and Duration>0 then self:ScheduleOnce(Duration, COORDINATE.StopSmoke, self, self.firename ) end end return self end --- Get the offset direction when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @return #number Direction in degrees. function COORDINATE:GetSmokeOffsetDirection() local direction = self.SmokeOffsetDirection or math.random(1,359) return direction end --- Set the offset direction when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random. -- @return #COORDINATE self function COORDINATE:SetSmokeOffsetDirection(Direction) if self then self.SmokeOffsetDirection = Direction or math.random(1,359) return self else COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359) end end --- Get the offset distance when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @return #number Distance Distance in meters. function COORDINATE:GetSmokeOffsetDistance() local distance = self.SmokeOffsetDistance or math.random(10,20) return distance end --- Set the offset distance when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20. -- @return #COORDINATE self function COORDINATE:SetSmokeOffsetDistance(Distance) if self then self.SmokeOffsetDistance = Distance or math.random(10,20) return self else COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20) end end --- Set the offset on when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @return #COORDINATE self function COORDINATE:SwitchSmokeOffsetOn() if self then self.SmokeOffset = true return self else COORDINATE.SmokeOffset = true end end --- Set the offset off when using `COORDINATE:Smoke()`. -- @param #COORDINATE self -- @return #COORDINATE self function COORDINATE:SwitchSmokeOffsetOff() if self then self.SmokeOffset = false return self else COORDINATE.SmokeOffset = false end end --- Stops smoking the point in a color. -- @param #COORDINATE self -- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) function COORDINATE:StopSmoke( name ) self:StopBigSmokeAndFire( name ) end --- Smoke the COORDINATE Green. -- @param #COORDINATE self -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @return #COORDINATE self function COORDINATE:SmokeGreen(Duration, Delay) self:Smoke( SMOKECOLOR.Green, Duration, Delay ) return self end --- Smoke the COORDINATE Red. -- @param #COORDINATE self -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @return #COORDINATE self function COORDINATE:SmokeRed(Duration, Delay) self:Smoke( SMOKECOLOR.Red, Duration, Delay ) return self end --- Smoke the COORDINATE White. -- @param #COORDINATE self -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @return #COORDINATE self function COORDINATE:SmokeWhite(Duration, Delay) self:Smoke( SMOKECOLOR.White, Duration, Delay ) return self end --- Smoke the COORDINATE Orange. -- @param #COORDINATE self -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @return #COORDINATE self function COORDINATE:SmokeOrange(Duration, Delay) self:Smoke( SMOKECOLOR.Orange, Duration, Delay ) return self end --- Smoke the COORDINATE Blue. -- @param #COORDINATE self -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @return #COORDINATE self function COORDINATE:SmokeBlue(Duration, Delay) self:Smoke( SMOKECOLOR.Blue, Duration, Delay ) return self end --- Big smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number Preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). -- @param #number Density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name ) self:F2( { preset=Preset, density=Density } ) Preset=Preset or BIGSMOKEPRESET.SmallSmokeAndFire Density=Density or 0.5 if Delay and Delay>0 then self:ScheduleOnce(Delay, COORDINATE.BigSmokeAndFire, self, Preset, Density, Duration, 0, Name) else self.firename = Name or "Fire-"..math.random(1,10000) trigger.action.effectSmokeBig( self:GetVec3(), Preset, Density, self.firename ) -- Stop smoke if Duration and Duration>0 then self:ScheduleOnce(Duration, COORDINATE.StopBigSmokeAndFire, self, self.firename ) end end return self end --- Stop big smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #string name (Optional) Name of the fire to stop it, if not using the same COORDINATE object. function COORDINATE:StopBigSmokeAndFire( name ) name = name or self.firename trigger.action.effectSmokeStop( name ) end --- Small smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number Density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name) return self end --- Medium smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name) return self end --- Large smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name) return self end --- Huge smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name) return self end --- Small smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name) return self end --- Medium smoke at the coordinate. -- @param #COORDINATE self -- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name) return self end --- Large smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name) return self end --- Huge smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. -- @return #COORDINATE self function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name ) self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name) return self end --- Flares the point in a color. -- @param #COORDINATE self -- @param Utilities.Utils#FLARECOLOR FlareColor -- @param DCS#Azimuth Azimuth (optional) The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:Flare( FlareColor, Azimuth ) self:F2( { FlareColor } ) trigger.action.signalFlare( self:GetVec3(), FlareColor, Azimuth and Azimuth or 0 ) end --- Flare the COORDINATE White. -- @param #COORDINATE self -- @param DCS#Azimuth Azimuth (optional) The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareWhite( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.White, Azimuth ) end --- Flare the COORDINATE Yellow. -- @param #COORDINATE self -- @param DCS#Azimuth Azimuth (optional) The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareYellow( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.Yellow, Azimuth ) end --- Flare the COORDINATE Green. -- @param #COORDINATE self -- @param DCS#Azimuth Azimuth (optional) The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareGreen( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.Green, Azimuth ) end --- Flare the COORDINATE Red. -- @param #COORDINATE self function COORDINATE:FlareRed( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.Red, Azimuth ) end do -- Markings --- Mark to All -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToAll( "This is a target for all players" ) function COORDINATE:MarkToAll( MarkText, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local text=Text or "" trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), ReadOnly, text) return MarkID end --- Mark to Coalition -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param Coalition -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalition( "This is a target for the red coalition", coalition.side.RED ) function COORDINATE:MarkToCoalition( MarkText, Coalition, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local text=Text or "" trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition, ReadOnly, text ) return MarkID end --- Mark to Red Coalition -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalitionRed( "This is a target for the red coalition" ) function COORDINATE:MarkToCoalitionRed( MarkText, ReadOnly, Text ) return self:MarkToCoalition( MarkText, coalition.side.RED, ReadOnly, Text ) end --- Mark to Blue Coalition -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalitionBlue( "This is a target for the blue coalition" ) function COORDINATE:MarkToCoalitionBlue( MarkText, ReadOnly, Text ) return self:MarkToCoalition( MarkText, coalition.side.BLUE, ReadOnly, Text ) end --- Mark to Group -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param Wrapper.Group#GROUP MarkGroup The @{Wrapper.Group} that receives the mark. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkGroup = GROUP:FindByName( "AttackGroup" ) -- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup ) function COORDINATE:MarkToGroup( MarkText, MarkGroup, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local text=Text or "" trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID(), ReadOnly, text ) return MarkID end --- Remove a mark -- @param #COORDINATE self -- @param #number MarkID The ID of the mark to be removed. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkGroup = GROUP:FindByName( "AttackGroup" ) -- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup ) -- <<< logic >>> -- TargetCoord:RemoveMark( MarkID ) -- The mark is now removed function COORDINATE:RemoveMark( MarkID ) trigger.action.removeMark( MarkID ) end --- Line to all. -- Creates a line on the F10 map from one point to another. -- @param #COORDINATE self -- @param #COORDINATE Endpoint COORDINATE to where the line is drawn. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:LineToAll(Endpoint, Coalition, Color, Alpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local vec3=Endpoint:GetVec3() Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 trigger.action.lineToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, LineType, ReadOnly, Text or "") return MarkID end --- Circle to all. -- Creates a circle on the map with a given radius, color, fill color, and outline. -- @param #COORDINATE self -- @param #number Radius Radius in meters. Default 1000 m. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:CircleToAll(Radius, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local vec3=self:GetVec3() Radius=Radius or 1000 Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end end -- Markings --- Rectangle to all. Creates a rectangle on the map from the COORDINATE in one corner to the end COORDINATE in the opposite corner. -- Creates a line on the F10 map from one point to another. -- @param #COORDINATE self -- @param #COORDINATE Endpoint COORDINATE in the opposite corner. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:RectToAll(Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local vec3=Endpoint:GetVec3() Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 trigger.action.rectToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end --- Creates a shape defined by 4 points on the F10 map. The first point is the current COORDINATE. The remaining three points need to be specified. -- @param #COORDINATE self -- @param #COORDINATE Coord2 Second COORDINATE of the quad shape. -- @param #COORDINATE Coord3 Third COORDINATE of the quad shape. -- @param #COORDINATE Coord4 Fourth COORDINATE of the quad shape. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local point1=self:GetVec3() local point2=Coord2:GetVec3() local point3=Coord3:GetVec3() local point4=Coord4:GetVec3() Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 trigger.action.quadToAll(Coalition, MarkID, point1, point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. -- @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. -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 local vecs={} vecs[1]=self:GetVec3() for i,coord in ipairs(Coordinates) do vecs[i+1]=coord:GetVec3() end if #vecs<3 then self:E("ERROR: A free form polygon needs at least three points!") elseif #vecs==3 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==4 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==5 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==6 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==7 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==8 then trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], Color, FillColor, LineType, ReadOnly, Text or "") elseif #vecs==9 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], 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 -- 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 "") -- Write command as string and execute that. Idea by Grimes https://forum.dcs.world/topic/324201-mark-to-all-function/#comment-5273793 local s=string.format("trigger.action.markupToAll(7, %d, %d,", Coalition, MarkID) for _,vec in pairs(vecs) do --s=s..string.format("%s,", UTILS._OneLineSerialize(vec)) s=s..string.format("{x=%.1f, y=%.1f, z=%.1f},", vec.x, vec.y, vec.z) end s=s..string.format("{%.3f, %.3f, %.3f, %.3f},", Color[1], Color[2], Color[3], Color[4]) s=s..string.format("{%.3f, %.3f, %.3f, %.3f},", FillColor[1], FillColor[2], FillColor[3], FillColor[4]) s=s..string.format("%d,", LineType or 1) s=s..string.format("%s", tostring(ReadOnly)) if Text and type(Text)=="string" and string.len(Text)>0 then s=s..string.format(", \"%s\"", tostring(Text)) end s=s..")" -- Execute string command local success=UTILS.DoString(s) if not success then self:E("ERROR: Could not draw polygon") env.info(s) end end return MarkID end --- Text to all. Creates a text imposed on the map at the COORDINATE. Text scales with the map. -- @param #COORDINATE self -- @param #string Text Text displayed on the F10 map. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.3. -- @param #number FontSize Font size. Default 14. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:TextToAll(Text, Coalition, Color, Alpha, FillColor, FillAlpha, FontSize, ReadOnly) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.3 FontSize=FontSize or 14 trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World") return MarkID end --- Arrow to all. Creates an arrow from the COORDINATE to the endpoint COORDINATE on the F10 map. There is no control over other dimensions of the arrow. -- @param #COORDINATE self -- @param #COORDINATE Endpoint COORDINATE where the tip of the arrow is pointing at. -- @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 (default). -- @param #number Alpha Transparency [0,1]. Default 1. -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. function COORDINATE:ArrowToAll(Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) local MarkID = UTILS.GetMarkID() if ReadOnly==nil then ReadOnly=false end local vec3=Endpoint:GetVec3() Coalition=Coalition or -1 Color=Color or {1,0,0} Color[4]=Alpha or 1.0 LineType=LineType or 1 FillColor=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 --trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World") trigger.action.arrowToAll(Coalition, MarkID, vec3, self:GetVec3(), Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end --- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate. -- @param #COORDINATE self -- @param #COORDINATE ToCoordinate -- @param #number Offset Height offset in meters. Default 2 m. -- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false. function COORDINATE:IsLOS( ToCoordinate, Offset ) Offset=Offset or 2 -- Measurement of visibility should not be from the ground, so Adding a hypothetical 2 meters to each Coordinate. local FromVec3 = self:GetVec3() FromVec3.y = FromVec3.y + Offset local ToVec3 = ToCoordinate:GetVec3() ToVec3.y = ToVec3.y + Offset local IsLOS = land.isVisible( FromVec3, ToVec3 ) return IsLOS end --- Returns if a Coordinate is in a certain Radius of this Coordinate in 2D plane using the X and Z axis. -- @param #COORDINATE self -- @param #COORDINATE Coordinate The coordinate that will be tested if it is in the radius of this coordinate. -- @param #number Radius The radius of the circle on the 2D plane around this coordinate. -- @return #boolean true if in the Radius. function COORDINATE:IsInRadius( Coordinate, Radius ) local InVec2 = self:GetVec2() local Vec2 = Coordinate:GetVec2() local InRadius = UTILS.IsInRadius( InVec2, Vec2, Radius) return InRadius end --- Returns if a Coordinate is in a certain radius of this Coordinate in 3D space using the X, Y and Z axis. -- So Radius defines the radius of the a Sphere in 3D space around this coordinate. -- @param #COORDINATE self -- @param #COORDINATE ToCoordinate The coordinate that will be tested if it is in the radius of this coordinate. -- @param #number Radius The radius of the sphere in the 3D space around this coordinate. -- @return #boolean true if in the Sphere. function COORDINATE:IsInSphere( Coordinate, Radius ) local InVec3 = self:GetVec3() local Vec3 = Coordinate:GetVec3() local InSphere = UTILS.IsInSphere( InVec3, Vec3, Radius) return InSphere end --- Get sun rise time for a specific date at the coordinate. -- @param #COORDINATE self -- @param #number Day The day. -- @param #number Month The month. -- @param #number Year The year. -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". function COORDINATE:GetSunriseAtDate(Day, Month, Year, InSeconds) -- Day of the year. local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) if InSeconds then return sunrise else return UTILS.SecondsToClock(sunrise, true) end end --- Get sun rise time for a specific day of the year at the coordinate. -- @param #COORDINATE self -- @param #number DayOfYear The day of the year. -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". function COORDINATE:GetSunriseAtDayOfYear(DayOfYear, InSeconds) local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) if InSeconds then return sunrise else return UTILS.SecondsToClock(sunrise, true) end end --- Get todays sun rise time. -- @param #COORDINATE self -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". function COORDINATE:GetSunrise(InSeconds) -- Get current day of the year. local DayOfYear=UTILS.GetMissionDayOfYear() -- Lat and long at this point. local Latitude, Longitude=self:GetLLDDM() -- GMT time diff. local Tdiff=UTILS.GMTToLocalTimeDifference() -- Sunrise in seconds of the day. local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) local date=UTILS.GetDCSMissionDate() -- Debug output. --self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%s sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), tonumber(sunrise) or "0", Tdiff)) if InSeconds or type(sunrise) == "string" then return sunrise else return UTILS.SecondsToClock(sunrise, true) end end --- Get minutes until the next sun rise at this coordinate. -- @param #COORDINATE self -- @param OnlyToday If true, only calculate the sun rise of today. If sun has already risen, the time in negative minutes since sunrise is reported. -- @return #number Minutes to the next sunrise. function COORDINATE:GetMinutesToSunrise(OnlyToday) -- Seconds of today local time=UTILS.SecondsOfToday() -- Next Sunrise in seconds. local sunrise=nil -- Time to sunrise. local delta=nil if OnlyToday then --- -- Sunrise of today --- sunrise=self:GetSunrise(true) delta=sunrise-time else --- -- Sunrise of tomorrow --- -- Tomorrows day of the year. local DayOfYear=UTILS.GetMissionDayOfYear()+1 local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) delta=sunrise+UTILS.SecondsToMidnight() end return delta/60 end --- Check if it is day, i.e. if the sun has risen about the horizon at this coordinate. -- @param #COORDINATE self -- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is day at 5:40 at third day after mission start. Default is to check right now. -- @return #boolean If true, it is day. If false, it is night time. function COORDINATE:IsDay(Clock) if Clock then local Time=UTILS.ClockToSeconds(Clock) local clock=UTILS.Split(Clock, "+")[1] -- Tomorrows day of the year. local DayOfYear=UTILS.GetMissionDayOfYear(Time) local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) if type(sunrise) == "string" or type(sunset) == "string" then if sunrise == "N/R" then return false end if sunset == "N/S" then return true end end local time=UTILS.ClockToSeconds(clock) -- Check if time is between sunrise and sunset. if time>sunrise and time<=sunset then return true else return false end else -- Todays sun rise in sec. local sunrise=self:GetSunrise(true) -- Todays sun set in sec. local sunset=self:GetSunset(true) if type(sunrise) == "string" or type(sunset) == "string" then if sunrise == "N/R" then return false end if sunset == "N/S" then return true end end -- Seconds passed since midnight. local time=UTILS.SecondsOfToday() -- Check if time is between sunrise and sunset. if time>sunrise and time<=sunset then return true else return false end end end --- Check if it is night, i.e. if the sun has set below the horizon at this coordinate. -- @param #COORDINATE self -- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is night at 5:40 at third day after mission start. Default is to check right now. -- @return #boolean If true, it is night. If false, it is day time. function COORDINATE:IsNight(Clock) return not self:IsDay(Clock) end --- Get sun set time for a specific date at the coordinate. -- @param #COORDINATE self -- @param #number Day The day. -- @param #number Month The month. -- @param #number Year The year. -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunset time, e.g. "20:41". function COORDINATE:GetSunsetAtDate(Day, Month, Year, InSeconds) -- Day of the year. local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) if InSeconds then return sunset else return UTILS.SecondsToClock(sunset, true) end end --- Get todays sun set time. -- @param #COORDINATE self -- @param #boolean InSeconds If true, return the sun set time in seconds. -- @return #string Sunrise time, e.g. "20:41". function COORDINATE:GetSunset(InSeconds) -- Get current day of the year. local DayOfYear=UTILS.GetMissionDayOfYear() -- Lat and long at this point. local Latitude, Longitude=self:GetLLDDM() -- GMT time diff. local Tdiff=UTILS.GMTToLocalTimeDifference() -- Sunrise in seconds of the day. local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) local date=UTILS.GetDCSMissionDate() -- Debug output. --self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%s sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), tostring(sunrise) or "0", Tdiff)) if InSeconds or type(sunrise) == "string" then return sunrise else return UTILS.SecondsToClock(sunrise, true) end end --- Get minutes until the next sun set at this coordinate. -- @param #COORDINATE self -- @param OnlyToday If true, only calculate the sun set of today. If sun has already set, the time in negative minutes since sunset is reported. -- @return #number Minutes to the next sunrise. function COORDINATE:GetMinutesToSunset(OnlyToday) -- Seconds of today local time=UTILS.SecondsOfToday() -- Next Sunset in seconds. local sunset=nil -- Time to sunrise. local delta=nil if OnlyToday then --- -- Sunset of today --- sunset=self:GetSunset(true) delta=sunset-time else --- -- Sunset of tomorrow --- -- Tomorrows day of the year. local DayOfYear=UTILS.GetMissionDayOfYear()+1 local Latitude, Longitude=self:GetLLDDM() local Tdiff=UTILS.GMTToLocalTimeDifference() sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) delta=sunset+UTILS.SecondsToMidnight() end return delta/60 end --- Return a BR string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA -- @param #number Precision Rounding precision, currently full km as default (=0) -- @return #string The BR text. function COORDINATE:ToStringBR( FromCoordinate, Settings, MagVar, Precision ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( FromCoordinate ) return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar, Precision ) end --- Return a BRA string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA -- @return #string The BR text. function COORDINATE:ToStringBRA( FromCoordinate, Settings, MagVar ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = FromCoordinate:Get2DDistance( self ) local Altitude = self:GetAltitudeText() return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, nil, MagVar ) end --- Create a BRAA NATO call string to this COORDINATE from the FromCOORDINATE. Note - BRA delivered if no aspect can be obtained and "Merged" if range < 3nm -- @param #COORDINATE self -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. -- @param #boolean Bogey Add "Bogey" at the end if true (not yet declared hostile or friendly) -- @param #boolean Spades Add "Spades" at the end if true (no IFF/VID ID yet known) -- @param #boolean SSML Add SSML tags speaking aspect as 0 1 2 and "brah" instead of BRAA -- @param #boolean Angels If true, altitude is e.g. "Angels 25" (i.e., a friendly plane), else "25 thousand" -- @param #boolean Zeros If using SSML, be aware that Google TTS will say "oh" and not "zero" for "0"; if Zeros is set to true, "0" will be replaced with "zero" -- @return #string The BRAA text. function COORDINATE:ToStringBRAANATO(FromCoordinate,Bogey,Spades,SSML,Angels,Zeros) -- Thanks to @Pikey local BRAANATO = "Merged." local currentCoord = FromCoordinate local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local bearing = UTILS.Round( UTILS.ToDegree( AngleRadians ),0 ) local magnetic = self:GetMagneticDeclination() or 0 bearing = bearing - magnetic local rangeMetres = self:Get2DDistance(currentCoord) local rangeNM = UTILS.Round( UTILS.MetersToNM(rangeMetres), 0) local aspect = self:ToStringAspect(currentCoord) local alt = UTILS.Round(UTILS.MetersToFeet(self.y)/1000,0)--*1000 local alttext = string.format("%d thousand",alt) if Angels then alttext = string.format("Angels %d",alt) end if alt < 1 then alttext = "very low" end -- corrected Track to be direction of travel of bogey (self in this case) local track = "Maneuver" if self.Heading then track = UTILS.BearingToCardinal(self.Heading) or "North" end if rangeNM > 3 then if SSML then -- google says "oh" instead of zero, be aware if Zeros then bearing = string.format("%03d",bearing) local AngleDegText = string.gsub(bearing,"%d","%1 ") -- "0 5 1 " AngleDegText = string.gsub(AngleDegText," $","") -- "0 5 1" AngleDegText = string.gsub(AngleDegText,"0","zero") if aspect == "" then BRAANATO = string.format("brah %s, %d miles, %s, Track %s", AngleDegText, rangeNM, alttext, track) else BRAANATO = string.format("brah %s, %d miles, %s, %s, Track %s", AngleDegText, rangeNM, alttext, aspect, track) end else if aspect == "" then BRAANATO = string.format("brah %03d, %d miles, %s, Track %s", bearing, rangeNM, alttext, track) else BRAANATO = string.format("brah %03d, %d miles, %s, %s, Track %s", bearing, rangeNM, alttext, aspect, track) end end if Bogey and Spades then BRAANATO = BRAANATO..", Bogey, Spades." elseif Bogey then BRAANATO = BRAANATO..", Bogey." elseif Spades then BRAANATO = BRAANATO..", Spades." else BRAANATO = BRAANATO.."." end else if aspect == "" then BRAANATO = string.format("BRA %03d, %d miles, %s, Track %s",bearing, rangeNM, alttext, track) else BRAANATO = string.format("BRAA %03d, %d miles, %s, %s, Track %s",bearing, rangeNM, alttext, aspect, track) end if Bogey and Spades then BRAANATO = BRAANATO..", Bogey, Spades." elseif Bogey then BRAANATO = BRAANATO..", Bogey." elseif Spades then BRAANATO = BRAANATO..", Spades." else BRAANATO = BRAANATO.."." end end end return BRAANATO end --- Return the BULLSEYE as COORDINATE Object -- @param #number Coalition Coalition of the bulls eye to return, e.g. coalition.side.BLUE -- @return #COORDINATE self -- @usage -- -- note the dot (.) here,not using the colon (:) -- local redbulls = COORDINATE.GetBullseyeCoordinate(coalition.side.RED) function COORDINATE.GetBullseyeCoordinate(Coalition) return COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) ) end --- Return a BULLS string out of the BULLS of the coalition to the COORDINATE. -- @param #COORDINATE self -- @param DCS#coalition.side Coalition The coalition. -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true, als get angle in magnetic -- @return #string The BR text. function COORDINATE:ToStringBULLS( Coalition, Settings, MagVar ) local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) ) local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( BullsCoordinate ) local Altitude = self:GetAltitudeText() return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) end --- Return an aspect string from a COORDINATE to the Angle of the object. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. -- @return #string The Aspect string, which is Hot, Cold or Flanking. function COORDINATE:ToStringAspect( TargetCoordinate ) local Heading = self.Heading local DirectionVec3 = self:GetDirectionVec3( TargetCoordinate ) local Angle = self:GetAngleDegrees( DirectionVec3 ) if Heading then local Aspect = Angle - Heading if Aspect > -135 and Aspect <= -45 then return "Flanking" end if Aspect > -45 and Aspect <= 45 then return "Hot" end if Aspect > 45 and Aspect <= 135 then return "Flanking" end if Aspect > 135 or Aspect <= -135 then return "Cold" end end return "" end --- Get Latitude and Longitude in Degrees Decimal Minutes (DDM). -- @param #COORDINATE self -- @return #number Latitude in DDM. -- @return #number Lontitude in DDM. function COORDINATE:GetLLDDM() return coord.LOtoLL( self:GetVec3() ) end --- Get Latitude & Longitude text. -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string LLText function COORDINATE:ToStringLL( Settings ) local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) return string.format('%f', lat) .. ' ' .. string.format('%f', lon) end --- Provides a Lat Lon string in Degree Minute Second format. -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The LL DMS Text function COORDINATE:ToStringLLDMS( Settings ) local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) return "LL DMS " .. UTILS.tostringLL( lat, lon, LL_Accuracy, true ) end --- Provides a Lat Lon string in Degree Decimal Minute format. -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The LL DDM Text function COORDINATE:ToStringLLDDM( Settings ) local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) return "LL DDM " .. UTILS.tostringLL( lat, lon, LL_Accuracy, false ) end --- Provides a MGRS string -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The MGRS Text function COORDINATE:ToStringMGRS( Settings ) local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) local MGRS = coord.LLtoMGRS( lat, lon ) return "MGRS " .. UTILS.tostringMGRS( MGRS, MGRS_Accuracy ) end --- Provides a COORDINATE from an MGRS String -- @param #COORDINATE self -- @param #string MGRSString MGRS String, e.g. "MGRS 37T DK 12345 12345" -- @return #COORDINATE self function COORDINATE:NewFromMGRSString( MGRSString ) local myparts = UTILS.Split(MGRSString," ") local northing = tostring(myparts[5]) or "" local easting = tostring(myparts[4]) or "" if string.len(easting) < 5 then easting = easting..string.rep("0",5-string.len(easting)) end if string.len(northing) < 5 then northing = northing..string.rep("0",5-string.len(northing)) end local MGRS = { UTMZone = myparts[2], MGRSDigraph = myparts[3], Easting = easting, Northing = northing, } local lat, lon = coord.MGRStoLL(MGRS) local point = coord.LLtoLO(lat, lon, 0) local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z}) return coord end --- Provides a COORDINATE from an MGRS Coordinate -- @param #COORDINATE self -- @param #string UTMZone UTM Zone, e.g. "37T" -- @param #string MGRSDigraph Digraph, e.g. "DK" -- @param #string Easting Meters easting - string in order to allow for leading zeros, e.g. "01234". Should be 5 digits. -- @param #string Northing Meters northing - string in order to allow for leading zeros, e.g. "12340". Should be 5 digits. -- @return #COORDINATE self function COORDINATE:NewFromMGRS( UTMZone, MGRSDigraph, Easting, Northing ) if string.len(Easting) < 5 then Easting = tostring(Easting..string.rep("0",5-string.len(Easting) )) end if string.len(Northing) < 5 then Northing = tostring(Northing..string.rep("0",5-string.len(Northing) )) end local MGRS = { UTMZone = UTMZone, MGRSDigraph = MGRSDigraph, Easting = tostring(Easting), Northing = tostring(Northing), } local lat, lon = coord.MGRStoLL(MGRS) local point = coord.LLtoLO(lat, lon, 0) local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z}) return coord end --- Provides a coordinate string of the point, based on a coordinate format system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param #COORDINATE ReferenceCoord The reference coordinate. -- @param #string ReferenceName The reference name. -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true also show angle in magnetic -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar ) self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS local IsAir = Controllable and Controllable:IsAirPlane() or false if IsAir then local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName else local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName end return nil end --- Provides a coordinate string of the point, based on a coordinate format system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param #COORDINATE ReferenceCoord The reference coordinate. -- @param #string ReferenceName The reference name. -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true also get the angle as magnetic -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringFromRPShort( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar ) self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS local IsAir = Controllable and Controllable:IsAirPlane() or false if IsAir then local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName else local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName end return nil end --- Provides a coordinate string of the point, based on the A2G coordinate format system. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2G( Controllable, Settings, MagVar ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS if Settings:IsA2G_BR() then -- If no Controllable is given to calculate the BR from, then MGRS will be used!!! if Controllable then local Coordinate = Controllable:GetCoordinate() return Controllable and self:ToStringBR( Coordinate, Settings, MagVar ) or self:ToStringMGRS( Settings ) else return self:ToStringMGRS( Settings ) end end if Settings:IsA2G_LL_DMS() then return self:ToStringLLDMS( Settings ) end if Settings:IsA2G_LL_DDM() then return self:ToStringLLDDM( Settings ) end if Settings:IsA2G_MGRS() then return self:ToStringMGRS( Settings ) end return nil end --- Provides a coordinate string of the point, based on the A2A coordinate format system. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2A( Controllable, Settings, MagVar ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS if Settings:IsA2A_BRAA() then if Controllable then local Coordinate = Controllable:GetCoordinate() return self:ToStringBRA( Coordinate, Settings, MagVar ) else return self:ToStringMGRS( Settings ) end end if Settings:IsA2A_BULLS() then local Coalition = Controllable:GetCoalition() return self:ToStringBULLS( Coalition, Settings, MagVar ) end if Settings:IsA2A_LL_DMS() then return self:ToStringLLDMS( Settings ) end if Settings:IsA2A_LL_DDM() then return self:ToStringLLDDM( Settings ) end if Settings:IsA2A_MGRS() then return self:ToStringMGRS( Settings ) end return nil end --- Provides a coordinate string of the point, based on a coordinate format system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The controllable to retrieve the settings from, otherwise the default settings will be chosen. -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToString( Controllable, Settings ) -- self:E( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS local ModeA2A = nil --[[ if Task then if Task:IsInstanceOf( TASK_A2A ) then ModeA2A = true else if Task:IsInstanceOf( TASK_A2G ) then ModeA2A = false else if Task:IsInstanceOf( TASK_CARGO ) then ModeA2A = false end if Task:IsInstanceOf( TASK_CAPTURE_ZONE ) then ModeA2A = false end end end end --]] if ModeA2A == nil then local IsAir = Controllable and ( Controllable:IsAirPlane() or Controllable:IsHelicopter() ) or false if IsAir then ModeA2A = true else ModeA2A = false end end if ModeA2A == true then return self:ToStringA2A( Controllable, Settings ) else return self:ToStringA2G( Controllable, Settings ) end return nil end --- Provides a pressure string of the point, based on a measurement system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The pressure text in the configured measurement system. function COORDINATE:ToStringPressure( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS return self:GetPressureText( nil, Settings ) end --- Provides a wind string of the point, based on a measurement system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The wind text in the configured measurement system. function COORDINATE:ToStringWind( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS return self:GetWindText( nil, Settings ) end --- Provides a temperature string of the point, based on a measurement system: -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS -- @return #string The temperature text in the configured measurement system. function COORDINATE:ToStringTemperature( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS return self:GetTemperatureText( nil, Settings ) end --- Function to check if a coordinate is in a steep (>8% elevation) area of the map -- @param #COORDINATE self -- @param #number Radius (Optional) Radius to check around the coordinate, defaults to 50m (100m diameter) -- @param #number Minelevation (Optional) Elevation from which on a area is defined as steep, defaults to 8% (8m height gain across 100 meters) -- @return #boolean IsSteep If true, area is steep -- @return #number MaxElevation Elevation in meters measured over 100m function COORDINATE:IsInSteepArea(Radius,Minelevation) local steep = false local elev = Minelevation or 8 local bdelta = 0 local h0 = self:GetLandHeight() local radius = Radius or 50 local diam = radius * 2 for i=0,150,30 do local polar = math.fmod(i+180,360) local c1 = self:Translate(radius,i,false,false) local c2 = self:Translate(radius,polar,false,false) local h1 = c1:GetLandHeight() local h2 = c2:GetLandHeight() local d1 = math.abs(h1-h2) local d2 = math.abs(h0-h1) local d3 = math.abs(h0-h2) local dm = d1 > d2 and d1 or d2 local dm1 = dm > d3 and dm or d3 bdelta = dm1 > bdelta and dm1 or bdelta self:T(string.format("d1=%d, d2=%d, d3=%d, max delta=%d",d1,d2,d3,bdelta)) end local steepness = bdelta / (radius / 100) if steepness >= elev then steep = true end return steep, math.floor(steepness) end --- Function to check if a coordinate is in a flat (<8% elevation) area of the map -- @param #COORDINATE self -- @param #number Radius (Optional) Radius to check around the coordinate, defaults to 50m (100m diameter) -- @param #number Minelevation (Optional) Elevation from which on a area is defined as steep, defaults to 8% (8m height gain across 100 meters) -- @return #boolean IsFlat If true, area is flat -- @return #number MaxElevation Elevation in meters measured over 100m function COORDINATE:IsInFlatArea(Radius,Minelevation) local steep, elev = self:IsInSteepArea(Radius,Minelevation) local flat = not steep return flat, elev end --- Return a random COORDINATE within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self -- @param DCS#Distance OuterRadius -- @param DCS#Distance InnerRadius -- @return #COORDINATE function COORDINATE:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) return COORDINATE:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) end --- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. -- @param #number SearchRadius Radius of the search area. -- @param #number PosRadius Required clear radius around each position. -- @param #number NumPositions Number of positions to find. -- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. nil if no positions are found. function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions) local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions) if clearPositions and #clearPositions > 0 then local coords = {} for _, pos in pairs(clearPositions) do local coord = COORDINATE:NewFromVec2(pos) table.insert(coords, coord) end return coords end return nil end end do --- The POINT_VEC3 class -- @type POINT_VEC3 -- @field #number x The x coordinate in 3D space. -- @field #number y The y coordinate in 3D space. -- @field #number z The z COORDINATE in 3D space. -- @field Utilities.Utils#SMOKECOLOR SmokeColor -- @field Utilities.Utils#FLARECOLOR FlareColor -- @field #POINT_VEC3.RoutePointAltType RoutePointAltType -- @field #POINT_VEC3.RoutePointType RoutePointType -- @field #POINT_VEC3.RoutePointAction RoutePointAction -- @extends #COORDINATE --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- **DEPRECATED - PLEASE USE COORDINATE!** -- -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. -- In order to keep the credibility of the the author, -- I want to emphasize that the formulas embedded in the MIST framework were created by Grimes or previous authors, -- who you can find on the Eagle Dynamics Forums. -- -- -- ## POINT_VEC3 constructor -- -- A new POINT_VEC3 object can be created with: -- -- * @{#POINT_VEC3.New}(): a 3D point. -- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCS#Vec3}. -- -- -- ## Manupulate the X, Y, Z coordinates of the POINT_VEC3 -- -- A POINT_VEC3 class works in 3D space. It contains internally an X, Y, Z coordinate. -- Methods exist to manupulate these coordinates. -- -- The current X, Y, Z axis can be retrieved with the methods @{#POINT_VEC3.GetX}(), @{#POINT_VEC3.GetY}(), @{#POINT_VEC3.GetZ}() respectively. -- The methods @{#POINT_VEC3.SetX}(), @{#POINT_VEC3.SetY}(), @{#POINT_VEC3.SetZ}() change the respective axis with a new value. -- The current axis values can be changed by using the methods @{#POINT_VEC3.AddX}(), @{#POINT_VEC3.AddY}(), @{#POINT_VEC3.AddZ}() -- to add or substract a value from the current respective axis value. -- Note that the Set and Add methods return the current POINT_VEC3 object, so these manipulation methods can be chained... For example: -- -- local Vec3 = PointVec3:AddX( 100 ):AddZ( 150 ):GetVec3() -- -- -- ## 3D calculation methods -- -- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method: -- -- -- ## Point Randomization -- -- Various methods exist to calculate random locations around a given 3D point. -- -- * @{#POINT_VEC3.GetRandomPointVec3InRadius}(): Provides a random 3D point around the current 3D point, in the given inner to outer band. -- -- -- @field #POINT_VEC3 POINT_VEC3 = { ClassName = "POINT_VEC3", Metric = true, RoutePointAltType = { BARO = "BARO", }, RoutePointType = { TakeOffParking = "TakeOffParking", TurningPoint = "Turning Point", }, RoutePointAction = { FromParkingArea = "From Parking Area", TurningPoint = "Turning Point", }, } --- RoutePoint AltTypes -- @type POINT_VEC3.RoutePointAltType -- @field BARO "BARO" --- RoutePoint Types -- @type POINT_VEC3.RoutePointType -- @field TakeOffParking "TakeOffParking" -- @field TurningPoint "Turning Point" --- RoutePoint Actions -- @type POINT_VEC3.RoutePointAction -- @field FromParkingArea "From Parking Area" -- @field TurningPoint "Turning Point" -- Constructor. --- Create a new POINT_VEC3 object. -- @param #POINT_VEC3 self -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing Upwards. -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the Right. -- @return Core.Point#POINT_VEC3 function POINT_VEC3:New( x, y, z ) local self = BASE:Inherit( self, COORDINATE:New( x, y, z ) ) -- Core.Point#POINT_VEC3 self:F2( self ) return self end end do --- @type POINT_VEC2 -- @field DCS#Distance x The x coordinate in meters. -- @field DCS#Distance y the y coordinate in meters. -- @extends Core.Point#COORDINATE --- Defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. -- -- **DEPRECATED - PLEASE USE COORDINATE!** -- -- ## POINT_VEC2 constructor -- -- A new POINT_VEC2 instance can be created with: -- -- * @{Core.Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. -- * @{Core.Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCS#Vec2}. -- -- ## Manupulate the X, Altitude, Y coordinates of the 2D point -- -- A POINT_VEC2 class works in 2D space, with an altitude setting. It contains internally an X, Altitude, Y coordinate. -- Methods exist to manupulate these coordinates. -- -- The current X, Altitude, Y axis can be retrieved with the methods @{#POINT_VEC2.GetX}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetY}() respectively. -- The methods @{#POINT_VEC2.SetX}(), @{#POINT_VEC2.SetAlt}(), @{#POINT_VEC2.SetY}() change the respective axis with a new value. -- The current Lat(itude), Alt(itude), Lon(gitude) values can also be retrieved with the methods @{#POINT_VEC2.GetLat}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetLon}() respectively. -- The current axis values can be changed by using the methods @{#POINT_VEC2.AddX}(), @{#POINT_VEC2.AddAlt}(), @{#POINT_VEC2.AddY}() -- to add or substract a value from the current respective axis value. -- Note that the Set and Add methods return the current POINT_VEC2 object, so these manipulation methods can be chained... For example: -- -- local Vec2 = PointVec2:AddX( 100 ):AddY( 2000 ):GetVec2() -- -- @field #POINT_VEC2 POINT_VEC2 = { ClassName = "POINT_VEC2", } --- POINT_VEC2 constructor. -- @param #POINT_VEC2 self -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to the Right. -- @param DCS#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. -- @return Core.Point#POINT_VEC2 function POINT_VEC2:New( x, y, LandHeightAdd ) local LandHeight = land.getHeight( { ["x"] = x, ["y"] = y } ) LandHeightAdd = LandHeightAdd or 0 LandHeight = LandHeight + LandHeightAdd local self = BASE:Inherit( self, COORDINATE:New( x, LandHeight, y ) ) -- Core.Point#POINT_VEC2 self:F2( self ) return self end end