use crate::db_client::ConnectivityWithCoordinates;
use crate::models::data::Tag;
use crate::models::EmbeddingVertexMultimodal001;
use crate::models::SegmentationSam3;
use crate::time_util::parse_rfc3339_to_unix_secs;
pub const CONNECTIVITY_TIMESTAMP_MATCH_TOLERANCE_SECS: f64 = 10.0;
pub fn connectivity_observation_unix_secs(
connectivity: &[ConnectivityWithCoordinates],
) -> Vec<Option<f64>> {
connectivity
.iter()
.map(|c| {
c.timestamp_start
.as_ref()
.and_then(|s| parse_rfc3339_to_unix_secs(s.as_str()))
})
.collect()
}
pub fn best_connectivity_match_index(
conn_unix: &[Option<f64>],
observation_unix_secs: f64,
tolerance_secs: f64,
) -> Option<usize> {
let mut best_idx = None;
let mut best_diff = tolerance_secs + 1.0;
for (i, &conn_ts) in conn_unix.iter().enumerate() {
if let Some(ct) = conn_ts {
let diff = (observation_unix_secs - ct).abs();
if diff <= tolerance_secs && diff < best_diff {
best_diff = diff;
best_idx = Some(i);
}
}
}
best_idx
}
fn apply_connectivity_observation_fields(
origin_heading: &mut Option<f64>,
sensor_yaw: &mut Option<f64>,
origin_height: &mut Option<f64>,
origin_location: &mut Option<String>,
c: &ConnectivityWithCoordinates,
) {
if c.heading.is_some() {
*origin_heading = c.heading;
*sensor_yaw = c.heading;
}
if c.altitude.is_some() {
*origin_height = c.altitude;
}
if let (Some(lat), Some(lon)) = (c.latitude, c.longitude) {
*origin_location = Some(Tag::format_location(lat, lon));
}
}
pub fn apply_connectivity_to_tag(tag: &mut Tag, c: &ConnectivityWithCoordinates) {
apply_connectivity_observation_fields(
&mut tag.origin_heading,
&mut tag.sensor_yaw,
&mut tag.origin_height,
&mut tag.origin_location,
c,
);
}
pub fn apply_connectivity_to_embedding_vertex(
row: &mut EmbeddingVertexMultimodal001,
c: &ConnectivityWithCoordinates,
) {
apply_connectivity_observation_fields(
&mut row.origin_heading,
&mut row.sensor_yaw,
&mut row.origin_height,
&mut row.origin_location,
c,
);
row.connectivity_id = c.id;
if let (Some(lat), Some(lon)) = (c.frame_center_latitude, c.frame_center_longitude) {
row.frame_center_location = Some(Tag::format_location(lat, lon));
}
if c.frame_center_altitude.is_some() {
row.frame_center_altitude = c.frame_center_altitude;
}
if c.frame_center_h14_index.is_some() {
row.frame_center_h14_index = c.frame_center_h14_index.clone();
row.frame_center_h13_index = c.frame_center_h13_index.clone();
row.frame_center_h12_index = c.frame_center_h12_index.clone();
row.frame_center_h11_index = c.frame_center_h11_index.clone();
}
}
pub fn apply_connectivity_to_segmentation_sam3(
row: &mut SegmentationSam3,
c: &ConnectivityWithCoordinates,
) {
apply_connectivity_observation_fields(
&mut row.origin_heading,
&mut row.sensor_yaw,
&mut row.origin_height,
&mut row.origin_location,
c,
);
}
pub fn enrich_tags_with_connectivity(
tags: &mut [Tag],
connectivity: &[ConnectivityWithCoordinates],
timestamp_match_tolerance_secs: f64,
) -> usize {
if connectivity.is_empty() {
return 0;
}
let conn_unix = connectivity_observation_unix_secs(connectivity);
let mut matched = 0;
for tag in tags.iter_mut() {
let tag_ts = tag
.timestamp_observation
.as_ref()
.and_then(|s| parse_rfc3339_to_unix_secs(s.as_str()));
let Some(tag_ts) = tag_ts else {
continue;
};
let Some(idx) =
best_connectivity_match_index(&conn_unix, tag_ts, timestamp_match_tolerance_secs)
else {
continue;
};
matched += 1;
apply_connectivity_to_tag(tag, &connectivity[idx]);
}
matched
}
pub fn enrich_segmentations_sam3_with_connectivity(
rows: &mut [SegmentationSam3],
connectivity: &[ConnectivityWithCoordinates],
timestamp_match_tolerance_secs: f64,
) -> usize {
if connectivity.is_empty() {
return 0;
}
let conn_unix = connectivity_observation_unix_secs(connectivity);
let mut matched = 0;
for row in rows.iter_mut() {
let ts = row
.timestamp_observation
.as_ref()
.and_then(|s| parse_rfc3339_to_unix_secs(s.as_str()));
let Some(ts) = ts else {
continue;
};
let Some(idx) =
best_connectivity_match_index(&conn_unix, ts, timestamp_match_tolerance_secs)
else {
continue;
};
matched += 1;
apply_connectivity_to_segmentation_sam3(row, &connectivity[idx]);
}
matched
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn embedding_receives_connectivity_id_and_frame_center() {
let mut embedding = EmbeddingVertexMultimodal001::default();
let connectivity = ConnectivityWithCoordinates {
id: Some(77),
frame_center_latitude: Some(19.7548),
frame_center_longitude: Some(-155.154),
frame_center_altitude: Some(125.0),
frame_center_h14_index: Some("8e2a1072b59ffff".to_string()),
frame_center_h11_index: Some("8b2a1072b59ffff".to_string()),
..Default::default()
};
apply_connectivity_to_embedding_vertex(&mut embedding, &connectivity);
assert_eq!(
embedding.frame_center_location.as_deref(),
Some("POINT(-155.154 19.7548)")
);
assert_eq!(embedding.frame_center_altitude, Some(125.0));
assert_eq!(embedding.connectivity_id, Some(77));
assert_eq!(
embedding.frame_center_h14_index.as_deref(),
Some("8e2a1072b59ffff")
);
assert_eq!(
embedding.frame_center_h11_index.as_deref(),
Some("8b2a1072b59ffff")
);
}
}