mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 16:13:30 +00:00
[WIP] Adding Drawing Cursor Over Time functions
This commit is contained in:
@@ -1 +1,2 @@
|
||||
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"
|
||||
}
|
||||
|
||||
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(
|
||||
ctx: Context,
|
||||
cursor_over_time: cot::digital_pointer::DigitalPointerPayload,
|
||||
|
||||
@@ -2,36 +2,72 @@ use arma_rs::Context;
|
||||
|
||||
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(
|
||||
ctx: Context,
|
||||
circle_payload: cot::draws::circle::CircleCoTPayload,
|
||||
) -> &'static str {
|
||||
let shape_circle_cot = circle_payload.to_cot();
|
||||
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);
|
||||
let (now, stale) = day_stale();
|
||||
let payload = shape_circle_cot.to_xml(&now, &stale);
|
||||
send_payload(ctx, payload);
|
||||
|
||||
"Sending Circle CoT to TCP server"
|
||||
}
|
||||
|
||||
pub fn send_ellipse_cot(ctx: Context) -> &'static str {
|
||||
let _ = ctx;
|
||||
"Not implemented: send_ellipse_cot"
|
||||
pub fn send_ellipse_cot(
|
||||
ctx: Context,
|
||||
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 {
|
||||
let _ = ctx;
|
||||
"Not implemented: send_ellipse_cot"
|
||||
pub fn send_rectangle_cot(
|
||||
ctx: Context,
|
||||
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 {
|
||||
let _ = ctx;
|
||||
"Not implemented: send_ellipse_cot"
|
||||
pub fn send_freedraw_cot(
|
||||
ctx: Context,
|
||||
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 {
|
||||
let _ = ctx;
|
||||
"Not implemented: send_ellipse_cot"
|
||||
pub fn send_vectordraw_cot(
|
||||
ctx: Context,
|
||||
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