mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 14:13:29 +00:00
Addded draw route rust structs
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
pub mod circle;
|
pub mod circle;
|
||||||
|
pub mod route;
|
||||||
pub mod shape;
|
pub mod shape;
|
||||||
|
|||||||
149
src/cot/draws/route.rs
Normal file
149
src/cot/draws/route.rs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
use arma_rs::{FromArma, FromArmaError};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct RoutePoint {
|
||||||
|
lat: f64,
|
||||||
|
lon: f64,
|
||||||
|
hae: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RoutePayload {
|
||||||
|
pub uuid: String,
|
||||||
|
pub points: String,
|
||||||
|
pub callsign: String,
|
||||||
|
pub stale_seconds: i64,
|
||||||
|
pub color: i32,
|
||||||
|
pub stroke_weight: f64,
|
||||||
|
pub method: String,
|
||||||
|
pub route_type: String,
|
||||||
|
pub direction: String,
|
||||||
|
pub checkpoint_interval: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for RoutePayload {
|
||||||
|
fn from_arma(data: String) -> Result<Self, FromArmaError> {
|
||||||
|
let (
|
||||||
|
uuid,
|
||||||
|
points,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
color,
|
||||||
|
stroke_weight,
|
||||||
|
method,
|
||||||
|
route_type,
|
||||||
|
direction,
|
||||||
|
checkpoint_interval,
|
||||||
|
) = <(
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
i64,
|
||||||
|
i32,
|
||||||
|
f64,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
i32,
|
||||||
|
)>::from_arma(data)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
uuid,
|
||||||
|
points,
|
||||||
|
callsign,
|
||||||
|
stale_seconds,
|
||||||
|
color,
|
||||||
|
stroke_weight,
|
||||||
|
method,
|
||||||
|
route_type,
|
||||||
|
direction,
|
||||||
|
checkpoint_interval: checkpoint_interval.max(1) as usize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoutePayload {
|
||||||
|
pub fn to_xml(&self, now: &str, stale: &str) -> String {
|
||||||
|
let points = parse_points(&self.points);
|
||||||
|
let links = route_links(&self.callsign, &points, self.checkpoint_interval);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
r#"<?xml version="1.0" encoding="UTF-8" ?><event version="2.0" uid="{uid}" type="b-m-r" time="{now}" start="{now}" stale="{stale}" how="h-e" access="Undefined"><point lat="0.0" lon="0.0" hae="9999999.0" ce="9999999.0" le="9999999.0"/><detail>{links}<link_attr planningmethod="{direction}" color="{color}" method="{method}" prefix="CP" style="0" type="Vehicle" stroke="{stroke_weight}" direction="{direction}" routetype="{route_type}" order="Ascending Check Points"/><creator uid="ARMATAK" callsign="ArmaTAK" time="{now}" type="a-f-G-U-C"/><strokeColor value="{color}"/><strokeWeight value="{stroke_weight}"/><strokeStyle value="solid"/><labels_on value="false"/><__routeinfo><__navcues/></__routeinfo><color value="{color}"/><remarks/><contact callsign="{callsign}"/><archive/><height_unit>1</height_unit></detail></event>"#,
|
||||||
|
uid = escape_attr(&self.uuid),
|
||||||
|
now = now,
|
||||||
|
stale = stale,
|
||||||
|
links = links,
|
||||||
|
direction = escape_attr(&self.direction),
|
||||||
|
color = self.color,
|
||||||
|
method = escape_attr(&self.method),
|
||||||
|
stroke_weight = self.stroke_weight.max(1.0),
|
||||||
|
route_type = escape_attr(&self.route_type),
|
||||||
|
callsign = escape_attr(&self.callsign)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn route_links(callsign: &str, points: &[RoutePoint], checkpoint_interval: usize) -> String {
|
||||||
|
let mut xml = String::new();
|
||||||
|
let last_index = points.len().saturating_sub(1);
|
||||||
|
let mut checkpoint_number = 1;
|
||||||
|
|
||||||
|
for (index, point) in points.iter().enumerate() {
|
||||||
|
let is_start = index == 0;
|
||||||
|
let is_end = index == last_index;
|
||||||
|
let is_checkpoint = !is_start && !is_end && index % checkpoint_interval == 0;
|
||||||
|
let point_callsign = if is_start {
|
||||||
|
format!("{} SP", callsign)
|
||||||
|
} else if is_end {
|
||||||
|
"VDO".to_string()
|
||||||
|
} else if is_checkpoint {
|
||||||
|
let name = format!("CP{}", checkpoint_number);
|
||||||
|
checkpoint_number += 1;
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
let link_type = if point_callsign.is_empty() {
|
||||||
|
"b-m-p-c"
|
||||||
|
} else {
|
||||||
|
"b-m-p-w"
|
||||||
|
};
|
||||||
|
|
||||||
|
xml.push_str(&format!(
|
||||||
|
r#"<link uid="{link_uid}" callsign="{callsign}" type="{link_type}" point="{lat},{lon},{hae}" remarks="" relation="c"/>"#,
|
||||||
|
link_uid = escape_attr(&Uuid::new_v4().to_string()),
|
||||||
|
callsign = escape_attr(&point_callsign),
|
||||||
|
link_type = link_type,
|
||||||
|
lat = point.lat,
|
||||||
|
lon = point.lon,
|
||||||
|
hae = point.hae
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
xml
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_points(raw: &str) -> Vec<RoutePoint> {
|
||||||
|
raw.split(';')
|
||||||
|
.filter_map(|entry| {
|
||||||
|
let parts: Vec<_> = entry.split(',').collect();
|
||||||
|
if parts.len() != 3 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(RoutePoint {
|
||||||
|
lat: parts[0].parse().ok()?,
|
||||||
|
lon: parts[1].parse().ok()?,
|
||||||
|
hae: parts[2].parse().ok()?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape_attr(value: &str) -> String {
|
||||||
|
value
|
||||||
|
.replace('&', "&")
|
||||||
|
.replace('"', """)
|
||||||
|
.replace('<', "<")
|
||||||
|
.replace('>', ">")
|
||||||
|
}
|
||||||
@@ -100,7 +100,8 @@ pub fn init() -> Extension {
|
|||||||
.command("ellipse", tcp::draw::send_ellipse_cot)
|
.command("ellipse", tcp::draw::send_ellipse_cot)
|
||||||
.command("rectangle", tcp::draw::send_rectangle_cot)
|
.command("rectangle", tcp::draw::send_rectangle_cot)
|
||||||
.command("free", tcp::draw::send_freedraw_cot)
|
.command("free", tcp::draw::send_freedraw_cot)
|
||||||
.command("vector", tcp::draw::send_vectordraw_cot),
|
.command("vector", tcp::draw::send_vectordraw_cot)
|
||||||
|
.command("route", tcp::draw::send_route_cot),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.group(
|
.group(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use arma_rs::Context;
|
use arma_rs::Context;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
use crate::{cot, tcp::send_payload};
|
use crate::{cot, tcp::send_payload};
|
||||||
|
|
||||||
@@ -71,3 +72,19 @@ pub fn send_vectordraw_cot(
|
|||||||
|
|
||||||
"Sending Tactical Graphic CoT to TCP server"
|
"Sending Tactical Graphic CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_route_cot(
|
||||||
|
ctx: Context,
|
||||||
|
route_payload: cot::draws::route::RoutePayload,
|
||||||
|
) -> &'static str {
|
||||||
|
let (now, stale) = payload_stale(route_payload.stale_seconds);
|
||||||
|
let payload = route_payload.to_xml(&now, &stale);
|
||||||
|
info!(
|
||||||
|
"Sending ATAK route '{}' ({} bytes)",
|
||||||
|
route_payload.callsign,
|
||||||
|
payload.len()
|
||||||
|
);
|
||||||
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
|
"Sending Route CoT to TCP server"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user