Squashed 'vendor/ruvector/' content from commit b64c2172

git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
commit d803bfe2b1
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
//! Configuration types for the perception pipeline.
//!
//! Provides tuning knobs for scene-graph construction, obstacle detection,
//! and the top-level perception configuration that bundles them together.
use serde::{Deserialize, Serialize};
// ---------------------------------------------------------------------------
// Scene-graph configuration
// ---------------------------------------------------------------------------
/// Tuning parameters for scene-graph construction from point clouds.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SceneGraphConfig {
/// Maximum distance between two points to be considered part of the same
/// cluster (metres).
pub cluster_radius: f64,
/// Minimum number of points required to form a valid cluster / object.
pub min_cluster_size: usize,
/// Hard cap on the number of objects the builder will emit.
pub max_objects: usize,
/// Maximum centre-to-centre distance for two objects to be connected by an
/// edge in the scene graph (metres).
pub edge_distance_threshold: f64,
}
impl Default for SceneGraphConfig {
fn default() -> Self {
Self {
cluster_radius: 0.5,
min_cluster_size: 3,
max_objects: 256,
edge_distance_threshold: 5.0,
}
}
}
// ---------------------------------------------------------------------------
// Obstacle configuration
// ---------------------------------------------------------------------------
/// Tuning parameters for the obstacle detector.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ObstacleConfig {
/// Minimum number of points that must fall inside a cluster to be
/// considered an obstacle.
pub min_obstacle_size: usize,
/// Maximum range from the robot within which obstacles are detected
/// (metres).
pub max_detection_range: f64,
/// Extra padding added around every detected obstacle (metres).
pub safety_margin: f64,
}
impl Default for ObstacleConfig {
fn default() -> Self {
Self {
min_obstacle_size: 3,
max_detection_range: 20.0,
safety_margin: 0.2,
}
}
}
// ---------------------------------------------------------------------------
// Top-level perception configuration
// ---------------------------------------------------------------------------
/// Aggregated configuration for the full perception pipeline.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct PerceptionConfig {
pub scene_graph: SceneGraphConfig,
pub obstacle: ObstacleConfig,
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scene_graph_config_defaults() {
let cfg = SceneGraphConfig::default();
assert!((cfg.cluster_radius - 0.5).abs() < f64::EPSILON);
assert_eq!(cfg.min_cluster_size, 3);
assert_eq!(cfg.max_objects, 256);
assert!((cfg.edge_distance_threshold - 5.0).abs() < f64::EPSILON);
}
#[test]
fn test_obstacle_config_defaults() {
let cfg = ObstacleConfig::default();
assert_eq!(cfg.min_obstacle_size, 3);
assert!((cfg.max_detection_range - 20.0).abs() < f64::EPSILON);
assert!((cfg.safety_margin - 0.2).abs() < f64::EPSILON);
}
#[test]
fn test_perception_config_defaults() {
let cfg = PerceptionConfig::default();
assert_eq!(cfg.scene_graph, SceneGraphConfig::default());
assert_eq!(cfg.obstacle, ObstacleConfig::default());
}
#[test]
fn test_scene_graph_config_serde_roundtrip() {
let cfg = SceneGraphConfig {
cluster_radius: 1.0,
min_cluster_size: 5,
max_objects: 128,
edge_distance_threshold: 3.0,
};
let json = serde_json::to_string(&cfg).unwrap();
let restored: SceneGraphConfig = serde_json::from_str(&json).unwrap();
assert_eq!(cfg, restored);
}
#[test]
fn test_obstacle_config_serde_roundtrip() {
let cfg = ObstacleConfig {
min_obstacle_size: 10,
max_detection_range: 50.0,
safety_margin: 0.5,
};
let json = serde_json::to_string(&cfg).unwrap();
let restored: ObstacleConfig = serde_json::from_str(&json).unwrap();
assert_eq!(cfg, restored);
}
#[test]
fn test_perception_config_serde_roundtrip() {
let cfg = PerceptionConfig::default();
let json = serde_json::to_string_pretty(&cfg).unwrap();
let restored: PerceptionConfig = serde_json::from_str(&json).unwrap();
assert_eq!(cfg, restored);
}
#[test]
fn test_config_clone_equality() {
let a = PerceptionConfig::default();
let b = a.clone();
assert_eq!(a, b);
}
#[test]
fn test_config_debug_format() {
let cfg = PerceptionConfig::default();
let dbg = format!("{:?}", cfg);
assert!(dbg.contains("PerceptionConfig"));
assert!(dbg.contains("SceneGraphConfig"));
assert!(dbg.contains("ObstacleConfig"));
}
#[test]
fn test_custom_perception_config() {
let cfg = PerceptionConfig {
scene_graph: SceneGraphConfig {
cluster_radius: 2.0,
min_cluster_size: 10,
max_objects: 64,
edge_distance_threshold: 10.0,
},
obstacle: ObstacleConfig {
min_obstacle_size: 5,
max_detection_range: 100.0,
safety_margin: 1.0,
},
};
assert!((cfg.scene_graph.cluster_radius - 2.0).abs() < f64::EPSILON);
assert_eq!(cfg.obstacle.min_obstacle_size, 5);
}
}