mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 13:53:28 +00:00
[WIP] Adding Drawing Cursor Over Time functions
This commit is contained in:
@@ -19,6 +19,24 @@ class CfgFunctions {
|
|||||||
class send_marker_cot {
|
class send_marker_cot {
|
||||||
file = "\armatak\armatak\addons\main\functions\api\fn_send_marker_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_marker_cot.sqf";
|
||||||
};
|
};
|
||||||
|
class report_marker {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_report_marker.sqf";
|
||||||
|
};
|
||||||
|
class draw_circle {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_draw_circle.sqf";
|
||||||
|
};
|
||||||
|
class draw_ellipse {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_draw_ellipse.sqf";
|
||||||
|
};
|
||||||
|
class draw_rectangle {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_draw_rectangle.sqf";
|
||||||
|
};
|
||||||
|
class draw_polyline {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_draw_polyline.sqf";
|
||||||
|
};
|
||||||
|
class draw_tactical_graphic {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\api\fn_draw_tactical_graphic.sqf";
|
||||||
|
};
|
||||||
class send_uas_platform_cot {
|
class send_uas_platform_cot {
|
||||||
file = "\armatak\armatak\addons\main\functions\api\fn_send_uas_platform_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_uas_platform_cot.sqf";
|
||||||
};
|
};
|
||||||
|
|||||||
41
addons/main/functions/api/fn_draw_circle.sqf
Normal file
41
addons/main/functions/api/fn_draw_circle.sqf
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// function name: armatak_fnc_draw_circle
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Sends an ATAK Drawing Tools circle CoT.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// 0: Center position or object <ARRAY|OBJECT>
|
||||||
|
// 1: Radius in meters <NUMBER>
|
||||||
|
// 2: Callsign/title <STRING> (default: "ArmaTAK Circle")
|
||||||
|
// 3: Stale time in seconds <NUMBER> (default: 86400)
|
||||||
|
// 4: Stroke color as signed ARGB int <NUMBER> (default: -1)
|
||||||
|
// 5: Fill color as signed ARGB int <NUMBER> (default: -1761607681)
|
||||||
|
// 6: Stroke weight <NUMBER> (default: 3)
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [player, 300, "Mortar Risk Area"] call armatak_fnc_draw_circle;
|
||||||
|
//
|
||||||
|
// Public: Yes
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_center", objNull, [objNull, []]],
|
||||||
|
["_radius", 100, [0]],
|
||||||
|
["_callsign", "ArmaTAK Circle", [""]],
|
||||||
|
["_staleSeconds", 86400, [0]],
|
||||||
|
["_strokeColor", -1, [0]],
|
||||||
|
["_fillColor", -1761607681, [0]],
|
||||||
|
["_strokeWeight", 3, [0]]
|
||||||
|
];
|
||||||
|
|
||||||
|
[
|
||||||
|
_center,
|
||||||
|
_radius,
|
||||||
|
_radius,
|
||||||
|
360,
|
||||||
|
_callsign,
|
||||||
|
_staleSeconds,
|
||||||
|
_strokeColor,
|
||||||
|
_fillColor,
|
||||||
|
_strokeWeight,
|
||||||
|
"",
|
||||||
|
"u-d-c-c"
|
||||||
|
] call armatak_fnc_draw_ellipse;
|
||||||
65
addons/main/functions/api/fn_draw_ellipse.sqf
Normal file
65
addons/main/functions/api/fn_draw_ellipse.sqf
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// function name: armatak_fnc_draw_ellipse
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Sends an ATAK Drawing Tools ellipse or circle CoT.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// 0: Center position or object <ARRAY|OBJECT>
|
||||||
|
// 1: Major radius in meters <NUMBER>
|
||||||
|
// 2: Minor radius in meters <NUMBER>
|
||||||
|
// 3: Rotation angle in degrees <NUMBER> (default: 0)
|
||||||
|
// 4: Callsign/title <STRING> (default: "ArmaTAK Ellipse")
|
||||||
|
// 5: Stale time in seconds <NUMBER> (default: 86400)
|
||||||
|
// 6: Stroke color as signed ARGB int <NUMBER> (default: -1)
|
||||||
|
// 7: Fill color as signed ARGB int <NUMBER> (default: -1761607681)
|
||||||
|
// 8: Stroke weight <NUMBER> (default: 3)
|
||||||
|
// 9: MilSym SIDC for tactical overlay <STRING> (default: "")
|
||||||
|
// 10: CoT type <STRING> (default: "u-d-c-e")
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [screenToWorld [0.5, 0.5], 250, 100, 45, "Support by Fire"] call armatak_fnc_draw_ellipse;
|
||||||
|
//
|
||||||
|
// Public: Yes
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_center", objNull, [objNull, []]],
|
||||||
|
["_major", 100, [0]],
|
||||||
|
["_minor", 50, [0]],
|
||||||
|
["_angle", 0, [0]],
|
||||||
|
["_callsign", "ArmaTAK Ellipse", [""]],
|
||||||
|
["_staleSeconds", 86400, [0]],
|
||||||
|
["_strokeColor", -1, [0]],
|
||||||
|
["_fillColor", -1761607681, [0]],
|
||||||
|
["_strokeWeight", 3, [0]],
|
||||||
|
["_milsym", "", [""]],
|
||||||
|
["_cotType", "u-d-c-e", [""]]
|
||||||
|
];
|
||||||
|
|
||||||
|
private _position = if (_center isEqualType objNull) then {
|
||||||
|
getPos _center
|
||||||
|
} else {
|
||||||
|
_center
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((count _position) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _altitude = _position param [2, 0, [0]];
|
||||||
|
private _realLocation = [_position select 0, _position select 1, _altitude] call armatak_client_fnc_convertClientLocation;
|
||||||
|
private _uuid = "armatak" callExtension ["uuid", []] select 0;
|
||||||
|
private _payload = [
|
||||||
|
_uuid,
|
||||||
|
_cotType,
|
||||||
|
_realLocation select 0,
|
||||||
|
_realLocation select 1,
|
||||||
|
_realLocation select 2,
|
||||||
|
_major max 1,
|
||||||
|
_minor max 1,
|
||||||
|
_angle,
|
||||||
|
_callsign,
|
||||||
|
_staleSeconds max 1,
|
||||||
|
_strokeColor,
|
||||||
|
_fillColor,
|
||||||
|
_strokeWeight max 1,
|
||||||
|
_milsym
|
||||||
|
];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:draw:ellipse", [_payload]];
|
||||||
78
addons/main/functions/api/fn_draw_polyline.sqf
Normal file
78
addons/main/functions/api/fn_draw_polyline.sqf
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// function name: armatak_fnc_draw_polyline
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Sends an ATAK Drawing Tools freeform line or polygon CoT.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// 0: Positions or objects <ARRAY>
|
||||||
|
// 1: Callsign/title <STRING> (default: "ArmaTAK Line")
|
||||||
|
// 2: Closed polygon <BOOL> (default: false)
|
||||||
|
// 3: Stale time in seconds <NUMBER> (default: 86400)
|
||||||
|
// 4: Stroke color as signed ARGB int <NUMBER> (default: -1)
|
||||||
|
// 5: Fill color as signed ARGB int <NUMBER> (default: -1761607681)
|
||||||
|
// 6: Stroke weight <NUMBER> (default: 3)
|
||||||
|
// 7: Stroke style <STRING> (default: "solid")
|
||||||
|
// 8: MilSym SIDC for tactical overlay <STRING> (default: "")
|
||||||
|
// 9: CoT type <STRING> (default: "u-d-f")
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [[pos player, screenToWorld [0.5, 0.5]], "Phase Line Blue"] call armatak_fnc_draw_polyline;
|
||||||
|
//
|
||||||
|
// Public: Yes
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_points", [], [[]]],
|
||||||
|
["_callsign", "ArmaTAK Line", [""]],
|
||||||
|
["_closed", false, [true]],
|
||||||
|
["_staleSeconds", 86400, [0]],
|
||||||
|
["_strokeColor", -1, [0]],
|
||||||
|
["_fillColor", -1761607681, [0]],
|
||||||
|
["_strokeWeight", 3, [0]],
|
||||||
|
["_strokeStyle", "solid", [""]],
|
||||||
|
["_milsym", "", [""]],
|
||||||
|
["_cotType", "u-d-f", [""]]
|
||||||
|
];
|
||||||
|
|
||||||
|
if ((count _points) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _pointStrings = [];
|
||||||
|
private _center = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _position = if (_x isEqualType objNull) then {
|
||||||
|
getPos _x
|
||||||
|
} else {
|
||||||
|
_x
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((count _position) >= 2) then {
|
||||||
|
private _altitude = _position param [2, 0, [0]];
|
||||||
|
private _realLocation = [_position select 0, _position select 1, _altitude] call armatak_client_fnc_convertClientLocation;
|
||||||
|
_pointStrings pushBack format ["%1,%2,%3", _realLocation select 0, _realLocation select 1, _realLocation select 2];
|
||||||
|
|
||||||
|
if (_center isEqualTo []) then {
|
||||||
|
_center = _realLocation;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} forEach _points;
|
||||||
|
|
||||||
|
if ((count _pointStrings) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _uuid = "armatak" callExtension ["uuid", []] select 0;
|
||||||
|
private _payload = [
|
||||||
|
_uuid,
|
||||||
|
_cotType,
|
||||||
|
_center select 0,
|
||||||
|
_center select 1,
|
||||||
|
_center select 2,
|
||||||
|
_pointStrings joinString ";",
|
||||||
|
_callsign,
|
||||||
|
_staleSeconds max 1,
|
||||||
|
_strokeColor,
|
||||||
|
_fillColor,
|
||||||
|
_strokeWeight max 1,
|
||||||
|
_strokeStyle,
|
||||||
|
_closed,
|
||||||
|
_milsym
|
||||||
|
];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:draw:free", [_payload]];
|
||||||
89
addons/main/functions/api/fn_draw_rectangle.sqf
Normal file
89
addons/main/functions/api/fn_draw_rectangle.sqf
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// function name: armatak_fnc_draw_rectangle
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Sends an ATAK Drawing Tools rectangle CoT from an Arma center, width, length, and bearing.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// 0: Center position or object <ARRAY|OBJECT>
|
||||||
|
// 1: Width in meters <NUMBER>
|
||||||
|
// 2: Length in meters <NUMBER>
|
||||||
|
// 3: Bearing in degrees <NUMBER> (default: 0)
|
||||||
|
// 4: Callsign/title <STRING> (default: "ArmaTAK Rectangle")
|
||||||
|
// 5: Stale time in seconds <NUMBER> (default: 86400)
|
||||||
|
// 6: Stroke color as signed ARGB int <NUMBER> (default: -1)
|
||||||
|
// 7: Fill color as signed ARGB int <NUMBER> (default: -1761607681)
|
||||||
|
// 8: Stroke weight <NUMBER> (default: 3)
|
||||||
|
// 9: MilSym SIDC for tactical overlay <STRING> (default: "")
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [screenToWorld [0.5, 0.5], 200, 500, 30, "Engagement Area"] call armatak_fnc_draw_rectangle;
|
||||||
|
//
|
||||||
|
// Public: Yes
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_center", objNull, [objNull, []]],
|
||||||
|
["_width", 100, [0]],
|
||||||
|
["_length", 100, [0]],
|
||||||
|
["_bearing", 0, [0]],
|
||||||
|
["_callsign", "ArmaTAK Rectangle", [""]],
|
||||||
|
["_staleSeconds", 86400, [0]],
|
||||||
|
["_strokeColor", -1, [0]],
|
||||||
|
["_fillColor", -1761607681, [0]],
|
||||||
|
["_strokeWeight", 3, [0]],
|
||||||
|
["_milsym", "", [""]]
|
||||||
|
];
|
||||||
|
|
||||||
|
private _centerPos = if (_center isEqualType objNull) then {
|
||||||
|
getPos _center
|
||||||
|
} else {
|
||||||
|
_center
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((count _centerPos) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _altitude = _centerPos param [2, 0, [0]];
|
||||||
|
private _halfWidth = (_width max 1) / 2;
|
||||||
|
private _halfLength = (_length max 1) / 2;
|
||||||
|
private _sin = sin _bearing;
|
||||||
|
private _cos = cos _bearing;
|
||||||
|
private _forward = [_sin, _cos, 0];
|
||||||
|
private _right = [_cos, -_sin, 0];
|
||||||
|
private _offsets = [
|
||||||
|
[(_right vectorMultiply -_halfWidth), (_forward vectorMultiply _halfLength)],
|
||||||
|
[(_right vectorMultiply _halfWidth), (_forward vectorMultiply _halfLength)],
|
||||||
|
[(_right vectorMultiply _halfWidth), (_forward vectorMultiply -_halfLength)],
|
||||||
|
[(_right vectorMultiply -_halfWidth), (_forward vectorMultiply -_halfLength)]
|
||||||
|
];
|
||||||
|
private _points = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _offset = (_x select 0) vectorAdd (_x select 1);
|
||||||
|
_points pushBack ([_centerPos select 0, _centerPos select 1, _altitude] vectorAdd _offset);
|
||||||
|
} forEach _offsets;
|
||||||
|
|
||||||
|
private _centerReal = [_centerPos select 0, _centerPos select 1, _altitude] call armatak_client_fnc_convertClientLocation;
|
||||||
|
private _pointStrings = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _realLocation = [_x select 0, _x select 1, _x select 2] call armatak_client_fnc_convertClientLocation;
|
||||||
|
_pointStrings pushBack format ["%1,%2,%3", _realLocation select 0, _realLocation select 1, _realLocation select 2];
|
||||||
|
} forEach _points;
|
||||||
|
|
||||||
|
private _uuid = "armatak" callExtension ["uuid", []] select 0;
|
||||||
|
private _payload = [
|
||||||
|
_uuid,
|
||||||
|
"u-d-r",
|
||||||
|
_centerReal select 0,
|
||||||
|
_centerReal select 1,
|
||||||
|
_centerReal select 2,
|
||||||
|
_pointStrings joinString ";",
|
||||||
|
_callsign,
|
||||||
|
_staleSeconds max 1,
|
||||||
|
_strokeColor,
|
||||||
|
_fillColor,
|
||||||
|
_strokeWeight max 1,
|
||||||
|
"solid",
|
||||||
|
false,
|
||||||
|
_milsym
|
||||||
|
];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:draw:rectangle", [_payload]];
|
||||||
75
addons/main/functions/api/fn_draw_tactical_graphic.sqf
Normal file
75
addons/main/functions/api/fn_draw_tactical_graphic.sqf
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// function name: armatak_fnc_draw_tactical_graphic
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Sends an ATAK Drawing Tools shape with a MilSym tactical graphic overlay.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// 0: Positions or objects <ARRAY>
|
||||||
|
// 1: MilSym SIDC <STRING>
|
||||||
|
// 2: Callsign/title <STRING> (default: "ArmaTAK Tactical Graphic")
|
||||||
|
// 3: Closed polygon <BOOL> (default: false)
|
||||||
|
// 4: Stale time in seconds <NUMBER> (default: 86400)
|
||||||
|
// 5: Stroke color as signed ARGB int <NUMBER> (default: -1)
|
||||||
|
// 6: Fill color as signed ARGB int <NUMBER> (default: -1761607681)
|
||||||
|
// 7: Stroke weight <NUMBER> (default: 3)
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [[pos player, screenToWorld [0.5, 0.5]], "GFGPOLAGM-----X", "Axis of Advance"] call armatak_fnc_draw_tactical_graphic;
|
||||||
|
//
|
||||||
|
// Public: Yes
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_points", [], [[]]],
|
||||||
|
["_milsym", "", [""]],
|
||||||
|
["_callsign", "ArmaTAK Tactical Graphic", [""]],
|
||||||
|
["_closed", false, [true]],
|
||||||
|
["_staleSeconds", 86400, [0]],
|
||||||
|
["_strokeColor", -1, [0]],
|
||||||
|
["_fillColor", -1761607681, [0]],
|
||||||
|
["_strokeWeight", 3, [0]]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (_milsym isEqualTo "") exitWith {""};
|
||||||
|
if ((count _points) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _pointStrings = [];
|
||||||
|
private _center = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _position = if (_x isEqualType objNull) then {
|
||||||
|
getPos _x
|
||||||
|
} else {
|
||||||
|
_x
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((count _position) >= 2) then {
|
||||||
|
private _altitude = _position param [2, 0, [0]];
|
||||||
|
private _realLocation = [_position select 0, _position select 1, _altitude] call armatak_client_fnc_convertClientLocation;
|
||||||
|
_pointStrings pushBack format ["%1,%2,%3", _realLocation select 0, _realLocation select 1, _realLocation select 2];
|
||||||
|
|
||||||
|
if (_center isEqualTo []) then {
|
||||||
|
_center = _realLocation;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} forEach _points;
|
||||||
|
|
||||||
|
if ((count _pointStrings) < 2) exitWith {""};
|
||||||
|
|
||||||
|
private _uuid = "armatak" callExtension ["uuid", []] select 0;
|
||||||
|
private _payload = [
|
||||||
|
_uuid,
|
||||||
|
"u-d-f",
|
||||||
|
_center select 0,
|
||||||
|
_center select 1,
|
||||||
|
_center select 2,
|
||||||
|
_pointStrings joinString ";",
|
||||||
|
_callsign,
|
||||||
|
_staleSeconds max 1,
|
||||||
|
_strokeColor,
|
||||||
|
_fillColor,
|
||||||
|
_strokeWeight max 1,
|
||||||
|
"solid",
|
||||||
|
_closed,
|
||||||
|
_milsym
|
||||||
|
];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:draw:vector", [_payload]];
|
||||||
@@ -1 +1,2 @@
|
|||||||
pub mod circle;
|
pub mod circle;
|
||||||
|
pub mod shape;
|
||||||
|
|||||||
317
src/cot/draws/shape.rs
Normal file
317
src/cot/draws/shape.rs
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
use arma_rs::{FromArma, FromArmaError};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct DrawPoint {
|
||||||
|
lat: f64,
|
||||||
|
lon: f64,
|
||||||
|
hae: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DrawEllipsePayload {
|
||||||
|
pub uuid: String,
|
||||||
|
pub cot_type: String,
|
||||||
|
pub center_lat: f64,
|
||||||
|
pub center_lon: f64,
|
||||||
|
pub center_hae: f32,
|
||||||
|
pub major: f64,
|
||||||
|
pub minor: f64,
|
||||||
|
pub angle: f32,
|
||||||
|
pub callsign: String,
|
||||||
|
pub stale_seconds: i64,
|
||||||
|
pub stroke_color: i32,
|
||||||
|
pub fill_color: i32,
|
||||||
|
pub stroke_weight: f64,
|
||||||
|
pub milsym: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DrawLinksPayload {
|
||||||
|
pub uuid: String,
|
||||||
|
pub cot_type: String,
|
||||||
|
pub center_lat: f64,
|
||||||
|
pub center_lon: f64,
|
||||||
|
pub center_hae: f32,
|
||||||
|
pub points: String,
|
||||||
|
pub callsign: String,
|
||||||
|
pub stale_seconds: i64,
|
||||||
|
pub stroke_color: i32,
|
||||||
|
pub fill_color: i32,
|
||||||
|
pub stroke_weight: f64,
|
||||||
|
pub stroke_style: String,
|
||||||
|
pub closed: bool,
|
||||||
|
pub milsym: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for DrawEllipsePayload {
|
||||||
|
fn from_arma(data: String) -> Result<Self, FromArmaError> {
|
||||||
|
let (
|
||||||
|
uuid,
|
||||||
|
cot_type,
|
||||||
|
center_lat,
|
||||||
|
center_lon,
|
||||||
|
center_hae,
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
angle,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
stroke_color,
|
||||||
|
fill_color,
|
||||||
|
stroke_weight,
|
||||||
|
milsym,
|
||||||
|
) = <(
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
f64,
|
||||||
|
f64,
|
||||||
|
f32,
|
||||||
|
f64,
|
||||||
|
f64,
|
||||||
|
f32,
|
||||||
|
String,
|
||||||
|
i64,
|
||||||
|
i32,
|
||||||
|
i32,
|
||||||
|
f64,
|
||||||
|
String,
|
||||||
|
)>::from_arma(data)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
uuid,
|
||||||
|
cot_type,
|
||||||
|
center_lat,
|
||||||
|
center_lon,
|
||||||
|
center_hae,
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
angle,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
stroke_color,
|
||||||
|
fill_color,
|
||||||
|
stroke_weight,
|
||||||
|
milsym,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for DrawLinksPayload {
|
||||||
|
fn from_arma(data: String) -> Result<Self, FromArmaError> {
|
||||||
|
let (
|
||||||
|
uuid,
|
||||||
|
cot_type,
|
||||||
|
center_lat,
|
||||||
|
center_lon,
|
||||||
|
center_hae,
|
||||||
|
points,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
stroke_color,
|
||||||
|
fill_color,
|
||||||
|
stroke_weight,
|
||||||
|
stroke_style,
|
||||||
|
closed,
|
||||||
|
milsym,
|
||||||
|
) = <(
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
f64,
|
||||||
|
f64,
|
||||||
|
f32,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
i64,
|
||||||
|
i32,
|
||||||
|
i32,
|
||||||
|
f64,
|
||||||
|
String,
|
||||||
|
bool,
|
||||||
|
String,
|
||||||
|
)>::from_arma(data)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
uuid,
|
||||||
|
cot_type,
|
||||||
|
center_lat,
|
||||||
|
center_lon,
|
||||||
|
center_hae,
|
||||||
|
points,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
stroke_color,
|
||||||
|
fill_color,
|
||||||
|
stroke_weight,
|
||||||
|
stroke_style,
|
||||||
|
closed,
|
||||||
|
milsym,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawEllipsePayload {
|
||||||
|
pub fn to_xml(&self, now: &str, stale: &str) -> String {
|
||||||
|
shape_event(
|
||||||
|
&self.uuid,
|
||||||
|
&self.cot_type,
|
||||||
|
self.center_lat,
|
||||||
|
self.center_lon,
|
||||||
|
self.center_hae,
|
||||||
|
now,
|
||||||
|
stale,
|
||||||
|
&self.callsign,
|
||||||
|
&ellipse_shape_detail(
|
||||||
|
&self.uuid,
|
||||||
|
self.major,
|
||||||
|
self.minor,
|
||||||
|
self.angle,
|
||||||
|
self.stroke_color,
|
||||||
|
self.fill_color,
|
||||||
|
self.stroke_weight,
|
||||||
|
),
|
||||||
|
self.stroke_color,
|
||||||
|
self.fill_color,
|
||||||
|
self.stroke_weight,
|
||||||
|
"solid",
|
||||||
|
&self.milsym,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawLinksPayload {
|
||||||
|
pub fn to_xml(&self, now: &str, stale: &str) -> String {
|
||||||
|
let points = parse_points(&self.points);
|
||||||
|
let shape_detail = links_detail(&points, self.closed);
|
||||||
|
|
||||||
|
shape_event(
|
||||||
|
&self.uuid,
|
||||||
|
&self.cot_type,
|
||||||
|
self.center_lat,
|
||||||
|
self.center_lon,
|
||||||
|
self.center_hae,
|
||||||
|
now,
|
||||||
|
stale,
|
||||||
|
&self.callsign,
|
||||||
|
&shape_detail,
|
||||||
|
self.stroke_color,
|
||||||
|
self.fill_color,
|
||||||
|
self.stroke_weight,
|
||||||
|
&self.stroke_style,
|
||||||
|
&self.milsym,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape_event(
|
||||||
|
uid: &str,
|
||||||
|
cot_type: &str,
|
||||||
|
lat: f64,
|
||||||
|
lon: f64,
|
||||||
|
hae: f32,
|
||||||
|
now: &str,
|
||||||
|
stale: &str,
|
||||||
|
callsign: &str,
|
||||||
|
shape_detail: &str,
|
||||||
|
stroke_color: i32,
|
||||||
|
fill_color: i32,
|
||||||
|
stroke_weight: f64,
|
||||||
|
stroke_style: &str,
|
||||||
|
milsym: &str,
|
||||||
|
) -> String {
|
||||||
|
let milsym_detail = if milsym.trim().is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!(r#"<__milsym id="{}" />"#, escape_attr(milsym))
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
r#"<?xml version="1.0" encoding="UTF-8" ?><event version="2.0" uid="{uid}" type="{cot_type}" time="{now}" start="{now}" stale="{stale}" how="h-e" access="Undefined"><point lat="{lat}" lon="{lon}" hae="{hae}" ce="10.9" le="9999999.0" /><detail>{shape_detail}<__shapeExtras cpvis="true" editable="true" /><contact callsign="{callsign}" /><remarks /><archive /><labels_on value="true" /><strokeColor value="{stroke_color}" /><strokeWeight value="{stroke_weight}" /><strokeStyle value="{stroke_style}" /><fillColor value="{fill_color}" /><precisionlocation altsrc="GPS" geopointsrc="GPS" />{milsym_detail}</detail></event>"#,
|
||||||
|
uid = escape_attr(uid),
|
||||||
|
cot_type = escape_attr(cot_type),
|
||||||
|
now = now,
|
||||||
|
stale = stale,
|
||||||
|
lat = lat,
|
||||||
|
lon = lon,
|
||||||
|
hae = hae,
|
||||||
|
shape_detail = shape_detail,
|
||||||
|
callsign = escape_attr(callsign),
|
||||||
|
stroke_color = stroke_color,
|
||||||
|
stroke_weight = stroke_weight,
|
||||||
|
stroke_style = escape_attr(stroke_style),
|
||||||
|
fill_color = fill_color,
|
||||||
|
milsym_detail = milsym_detail
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ellipse_shape_detail(
|
||||||
|
uid: &str,
|
||||||
|
major: f64,
|
||||||
|
minor: f64,
|
||||||
|
angle: f32,
|
||||||
|
stroke_color: i32,
|
||||||
|
fill_color: i32,
|
||||||
|
stroke_weight: f64,
|
||||||
|
) -> String {
|
||||||
|
format!(
|
||||||
|
r#"<shape><ellipse major="{major}" minor="{minor}" angle="{angle}" /><link uid="{style_uid}" type="b-x-KmlStyle" relation="p-c"><Style><LineStyle><color>{stroke_hex}</color><width>{stroke_weight}</width></LineStyle><PolyStyle><color>{fill_hex}</color></PolyStyle></Style></link></shape>"#,
|
||||||
|
major = major,
|
||||||
|
minor = minor,
|
||||||
|
angle = angle,
|
||||||
|
style_uid = escape_attr(&format!("{}.Style", uid)),
|
||||||
|
stroke_hex = argb_hex(stroke_color),
|
||||||
|
stroke_weight = stroke_weight,
|
||||||
|
fill_hex = argb_hex(fill_color)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn links_detail(points: &[DrawPoint], closed: bool) -> String {
|
||||||
|
let mut detail = String::new();
|
||||||
|
|
||||||
|
for point in points {
|
||||||
|
detail.push_str(&link_detail(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
if closed {
|
||||||
|
if let Some(first) = points.first() {
|
||||||
|
detail.push_str(&link_detail(first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detail
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link_detail(point: &DrawPoint) -> String {
|
||||||
|
format!(
|
||||||
|
r#"<link point="{lat},{lon},{hae}" />"#,
|
||||||
|
lat = point.lat,
|
||||||
|
lon = point.lon,
|
||||||
|
hae = point.hae
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_points(raw: &str) -> Vec<DrawPoint> {
|
||||||
|
raw.split(';')
|
||||||
|
.filter_map(|entry| {
|
||||||
|
let parts: Vec<_> = entry.split(',').collect();
|
||||||
|
if parts.len() != 3 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(DrawPoint {
|
||||||
|
lat: parts[0].parse().ok()?,
|
||||||
|
lon: parts[1].parse().ok()?,
|
||||||
|
hae: parts[2].parse().ok()?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argb_hex(color: i32) -> String {
|
||||||
|
format!("{:08x}", color as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape_attr(value: &str) -> String {
|
||||||
|
value
|
||||||
|
.replace('&', "&")
|
||||||
|
.replace('"', """)
|
||||||
|
.replace('<', "<")
|
||||||
|
.replace('>', ">")
|
||||||
|
}
|
||||||
@@ -19,6 +19,16 @@ pub fn send_marker_cot(
|
|||||||
"Sending Marker Cursor Over Time to TCP server"
|
"Sending Marker Cursor Over Time to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_report_marker_cot(
|
||||||
|
ctx: Context,
|
||||||
|
cursor_over_time: cot::report_marker::ReportMarkerCoTPayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let payload = cursor_over_time.to_cot().convert_to_xml();
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Report Marker Cursor Over Time to TCP server"
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_digital_pointer_cot(
|
pub fn send_digital_pointer_cot(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
cursor_over_time: cot::digital_pointer::DigitalPointerPayload,
|
cursor_over_time: cot::digital_pointer::DigitalPointerPayload,
|
||||||
|
|||||||
@@ -2,36 +2,72 @@ use arma_rs::Context;
|
|||||||
|
|
||||||
use crate::{cot, tcp::send_payload};
|
use crate::{cot, tcp::send_payload};
|
||||||
|
|
||||||
|
fn day_stale() -> (String, String) {
|
||||||
|
let now = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
||||||
|
let stale = (chrono::Utc::now() + chrono::Duration::days(1))
|
||||||
|
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
||||||
|
(now, stale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn payload_stale(stale_seconds: i64) -> (String, String) {
|
||||||
|
let now = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
||||||
|
let stale = (chrono::Utc::now() + chrono::Duration::seconds(stale_seconds.max(1)))
|
||||||
|
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
||||||
|
(now, stale)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_circle_cot(
|
pub fn send_circle_cot(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
circle_payload: cot::draws::circle::CircleCoTPayload,
|
circle_payload: cot::draws::circle::CircleCoTPayload,
|
||||||
) -> &'static str {
|
) -> &'static str {
|
||||||
let shape_circle_cot = circle_payload.to_cot();
|
let shape_circle_cot = circle_payload.to_cot();
|
||||||
let now = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
let (now, stale) = day_stale();
|
||||||
let stale = (chrono::Utc::now() + chrono::Duration::days(1))
|
|
||||||
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
|
|
||||||
let payload = shape_circle_cot.to_xml(&now, &stale);
|
let payload = shape_circle_cot.to_xml(&now, &stale);
|
||||||
send_payload(ctx, payload);
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
"Sending Circle CoT to TCP server"
|
"Sending Circle CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_ellipse_cot(ctx: Context) -> &'static str {
|
pub fn send_ellipse_cot(
|
||||||
let _ = ctx;
|
ctx: Context,
|
||||||
"Not implemented: send_ellipse_cot"
|
ellipse_payload: cot::draws::shape::DrawEllipsePayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let (now, stale) = payload_stale(ellipse_payload.stale_seconds);
|
||||||
|
let payload = ellipse_payload.to_xml(&now, &stale);
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Ellipse CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_rectangle_cot(ctx: Context) -> &'static str {
|
pub fn send_rectangle_cot(
|
||||||
let _ = ctx;
|
ctx: Context,
|
||||||
"Not implemented: send_ellipse_cot"
|
rectangle_payload: cot::draws::shape::DrawLinksPayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let (now, stale) = payload_stale(rectangle_payload.stale_seconds);
|
||||||
|
let payload = rectangle_payload.to_xml(&now, &stale);
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Rectangle CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_freedraw_cot(ctx: Context) -> &'static str {
|
pub fn send_freedraw_cot(
|
||||||
let _ = ctx;
|
ctx: Context,
|
||||||
"Not implemented: send_ellipse_cot"
|
freedraw_payload: cot::draws::shape::DrawLinksPayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let (now, stale) = payload_stale(freedraw_payload.stale_seconds);
|
||||||
|
let payload = freedraw_payload.to_xml(&now, &stale);
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Free Draw CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_vectordraw_cot(ctx: Context) -> &'static str {
|
pub fn send_vectordraw_cot(
|
||||||
let _ = ctx;
|
ctx: Context,
|
||||||
"Not implemented: send_ellipse_cot"
|
vector_payload: cot::draws::shape::DrawLinksPayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let (now, stale) = payload_stale(vector_payload.stale_seconds);
|
||||||
|
let payload = vector_payload.to_xml(&now, &stale);
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Tactical Graphic CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user