use crate::builtin_interfaces::msg as bi;
use crate::geographic_msgs::msg as geog;
use crate::geometry_msgs::msg as geo;
use crate::sensor_msgs::msg as sensor;
use crate::tf2_msgs::msg as tf2;
use crate::vision_msgs::msg as vision;
use zerodds_spatial_dds::builtin;
use zerodds_spatial_dds::spatial::common::FrameRef;
use zerodds_spatial_dds::spatial::core::{FrameTransform, FramedPose, GeoPose, PoseSE3};
use zerodds_spatial_dds::spatial::semantics::{Detection3D, Detection3DSet};
use zerodds_spatial_dds::spatial::vio::ImuSample;
fn time_to_ros(t: &builtin::Time) -> bi::Time {
bi::Time {
sec: t.sec,
nanosec: t.nanosec,
}
}
fn time_from_ros(t: &bi::Time) -> builtin::Time {
builtin::Time {
sec: t.sec,
nanosec: t.nanosec,
}
}
fn header(stamp: &builtin::Time, frame_id: &str) -> crate::std_msgs::msg::Header {
crate::std_msgs::msg::Header {
stamp: time_to_ros(stamp),
frame_id: frame_id.to_string(),
}
}
fn frame_id_of(fr: &FrameRef) -> &str {
if fr.fqn.is_empty() { &fr.uuid } else { &fr.fqn }
}
fn frame_ref_from_id(frame_id: &str) -> FrameRef {
FrameRef {
fqn: frame_id.to_string(),
..Default::default()
}
}
fn point_from_vec3(v: &[f64; 3]) -> geo::Point {
geo::Point {
x: v[0],
y: v[1],
z: v[2],
}
}
fn vec3_from_point(p: &geo::Point) -> [f64; 3] {
[p.x, p.y, p.z]
}
fn vector3_from_vec3(v: &[f64; 3]) -> geo::Vector3 {
geo::Vector3 {
x: v[0],
y: v[1],
z: v[2],
}
}
fn vec3_from_vector3(v: &geo::Vector3) -> [f64; 3] {
[v.x, v.y, v.z]
}
fn quat_to_ros(q: &[f64; 4]) -> geo::Quaternion {
geo::Quaternion {
x: q[0],
y: q[1],
z: q[2],
w: q[3],
}
}
fn quat_from_ros(q: &geo::Quaternion) -> [f64; 4] {
[q.x, q.y, q.z, q.w]
}
fn pose_se3_to_ros(p: &PoseSE3) -> geo::Pose {
geo::Pose {
position: point_from_vec3(&p.t),
orientation: quat_to_ros(&p.q),
}
}
fn pose_se3_from_ros(p: &geo::Pose) -> PoseSE3 {
PoseSE3 {
t: vec3_from_point(&p.position),
q: quat_from_ros(&p.orientation),
}
}
fn cov6_from(pos: &[f64; 9], rot: &[f64; 9]) -> [f64; 36] {
let mut c = [0.0f64; 36];
for r in 0..3 {
for col in 0..3 {
c[r * 6 + col] = pos[r * 3 + col];
c[(r + 3) * 6 + (col + 3)] = rot[r * 3 + col];
}
}
c
}
fn cov_blocks_from6(c: &[f64; 36]) -> ([f64; 9], [f64; 9]) {
let mut pos = [0.0f64; 9];
let mut rot = [0.0f64; 9];
for r in 0..3 {
for col in 0..3 {
pos[r * 3 + col] = c[r * 6 + col];
rot[r * 3 + col] = c[(r + 3) * 6 + (col + 3)];
}
}
(pos, rot)
}
#[must_use]
pub fn framed_pose_to_ros(f: &FramedPose) -> geo::PoseStamped {
geo::PoseStamped {
header: header(&f.stamp, frame_id_of(&f.frame_ref)),
pose: pose_se3_to_ros(&f.pose),
}
}
#[must_use]
pub fn framed_pose_from_ros(m: &geo::PoseStamped) -> FramedPose {
FramedPose {
pose: pose_se3_from_ros(&m.pose),
frame_ref: frame_ref_from_id(&m.header.frame_id),
cov: Default::default(),
stamp: time_from_ros(&m.header.stamp),
}
}
#[must_use]
pub fn frame_transform_to_ros(t: &FrameTransform) -> geo::TransformStamped {
geo::TransformStamped {
header: header(&t.stamp, frame_id_of(&t.parent_ref)),
child_frame_id: frame_id_of(&t.child_ref).to_string(),
transform: geo::Transform {
translation: vector3_from_vec3(&t.T_parent_child.t),
rotation: quat_to_ros(&t.T_parent_child.q),
},
}
}
#[must_use]
pub fn frame_transform_from_ros(m: &geo::TransformStamped) -> FrameTransform {
FrameTransform {
transform_id: String::new(),
parent_ref: frame_ref_from_id(&m.header.frame_id),
child_ref: frame_ref_from_id(&m.child_frame_id),
T_parent_child: PoseSE3 {
t: vec3_from_vector3(&m.transform.translation),
q: quat_from_ros(&m.transform.rotation),
},
stamp: time_from_ros(&m.header.stamp),
cov: Default::default(),
}
}
#[must_use]
pub fn tf_message_from(transforms: &[FrameTransform]) -> tf2::TFMessage {
tf2::TFMessage {
transforms: transforms.iter().map(frame_transform_to_ros).collect(),
}
}
#[must_use]
pub fn geo_pose_to_ros(g: &GeoPose) -> geog::GeoPoseStamped {
geog::GeoPoseStamped {
header: header(&g.stamp, frame_id_of(&g.frame_ref)),
pose: geog::GeoPose {
position: geog::GeoPoint {
latitude: g.lat_deg,
longitude: g.lon_deg,
altitude: g.alt_m,
},
orientation: quat_to_ros(&g.q),
},
}
}
#[must_use]
pub fn geo_pose_from_ros(m: &geog::GeoPoseStamped) -> GeoPose {
GeoPose {
lat_deg: m.pose.position.latitude,
lon_deg: m.pose.position.longitude,
alt_m: m.pose.position.altitude,
q: quat_from_ros(&m.pose.orientation),
frame_ref: frame_ref_from_id(&m.header.frame_id),
stamp: time_from_ros(&m.header.stamp),
..Default::default()
}
}
#[must_use]
pub fn detection3d_to_ros(d: &Detection3D) -> vision::Detection3D {
let center = geo::Pose {
position: point_from_vec3(&d.center),
orientation: quat_to_ros(&d.q),
};
let covariance = if d.has_covariance {
cov6_from(&d.cov_pos, &d.cov_rot)
} else {
[0.0f64; 36]
};
vision::Detection3D {
header: header(&d.stamp, frame_id_of(&d.frame_ref)),
results: vec![vision::ObjectHypothesisWithPose {
hypothesis: vision::ObjectHypothesis {
class_id: d.class_id.clone(),
score: f64::from(d.score),
},
pose: geo::PoseWithCovariance {
pose: center.clone(),
covariance,
},
}],
bbox: vision::BoundingBox3D {
center,
size: vector3_from_vec3(&d.size),
},
id: d.det_id.clone(),
}
}
#[must_use]
pub fn detection3d_from_ros(m: &vision::Detection3D) -> Detection3D {
let (class_id, score) = m
.results
.first()
.map(|r| (r.hypothesis.class_id.clone(), r.hypothesis.score as f32))
.unwrap_or_default();
let has_covariance = m
.results
.first()
.is_some_and(|r| r.pose.covariance.iter().any(|&x| x != 0.0));
let (cov_pos, cov_rot) = m
.results
.first()
.map(|r| cov_blocks_from6(&r.pose.covariance))
.unwrap_or(([0.0; 9], [0.0; 9]));
Detection3D {
det_id: m.id.clone(),
frame_ref: frame_ref_from_id(&m.header.frame_id),
class_id,
score,
center: vec3_from_point(&m.bbox.center.position),
size: vec3_from_vector3(&m.bbox.size),
q: quat_from_ros(&m.bbox.center.orientation),
has_covariance,
cov_pos,
cov_rot,
stamp: time_from_ros(&m.header.stamp),
..Default::default()
}
}
#[must_use]
pub fn detection3d_set_to_ros(s: &Detection3DSet) -> vision::Detection3DArray {
vision::Detection3DArray {
header: header(&s.stamp, frame_id_of(&s.frame_ref)),
detections: s.dets.iter().map(detection3d_to_ros).collect(),
}
}
#[must_use]
pub fn detection3d_set_from_ros(m: &vision::Detection3DArray) -> Detection3DSet {
Detection3DSet {
frame_ref: frame_ref_from_id(&m.header.frame_id),
dets: m.detections.iter().map(detection3d_from_ros).collect(),
stamp: time_from_ros(&m.header.stamp),
..Default::default()
}
}
#[must_use]
pub fn imu_to_ros(s: &ImuSample) -> sensor::Imu {
let mut orientation_covariance = [0.0f64; 9];
orientation_covariance[0] = -1.0;
sensor::Imu {
header: header(&s.stamp, &s.imu_id),
orientation: geo::Quaternion {
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0,
},
orientation_covariance,
angular_velocity: vector3_from_vec3(&s.gyro),
angular_velocity_covariance: [0.0; 9],
linear_acceleration: vector3_from_vec3(&s.accel),
linear_acceleration_covariance: [0.0; 9],
}
}
#[must_use]
pub fn imu_from_ros(m: &sensor::Imu) -> ImuSample {
ImuSample {
imu_id: m.header.frame_id.clone(),
accel: vec3_from_vector3(&m.linear_acceleration),
gyro: vec3_from_vector3(&m.angular_velocity),
stamp: time_from_ros(&m.header.stamp),
..Default::default()
}
}
impl From<&FramedPose> for geo::PoseStamped {
fn from(f: &FramedPose) -> Self {
framed_pose_to_ros(f)
}
}
impl From<&FrameTransform> for geo::TransformStamped {
fn from(t: &FrameTransform) -> Self {
frame_transform_to_ros(t)
}
}
impl From<&GeoPose> for geog::GeoPoseStamped {
fn from(g: &GeoPose) -> Self {
geo_pose_to_ros(g)
}
}
impl From<&Detection3D> for vision::Detection3D {
fn from(d: &Detection3D) -> Self {
detection3d_to_ros(d)
}
}
impl From<&Detection3DSet> for vision::Detection3DArray {
fn from(s: &Detection3DSet) -> Self {
detection3d_set_to_ros(s)
}
}
impl From<&ImuSample> for sensor::Imu {
fn from(s: &ImuSample) -> Self {
imu_to_ros(s)
}
}