mecha10_sim/services/
simulation.rs1#![allow(dead_code)]
2
3use crate::paths;
9use crate::sim::{EnvironmentSelector, RobotGenerator, RobotProfile};
10use anyhow::Result;
11use std::path::{Path, PathBuf};
12
13pub struct SimulationService {
14 base_path: PathBuf,
15}
16
17impl SimulationService {
18 pub fn new() -> Self {
20 Self {
21 base_path: PathBuf::from(paths::project::SIMULATION_OUTPUT_DIR),
22 }
23 }
24
25 pub fn with_base_path(base_path: impl Into<PathBuf>) -> Self {
31 Self {
32 base_path: base_path.into(),
33 }
34 }
35
36 pub fn generate(
45 &self,
46 config_path: &Path,
47 output_path: &Path,
48 max_envs: usize,
49 min_score: i32,
50 ) -> Result<GenerationResult> {
51 let profile = RobotProfile::from_config_file(config_path)?;
52
53 let robot_output = output_path.join("robot.tscn");
54 let robot_generator = RobotGenerator::from_config_file(config_path)?;
55 robot_generator.generate(&robot_output)?;
56
57 let selector = EnvironmentSelector::new()?;
58 let matches = selector.select_environments(&profile, max_envs)?;
59
60 let filtered_matches: Vec<_> = matches.into_iter().filter(|m| m.score >= min_score).collect();
61
62 if filtered_matches.is_empty() {
63 return Err(anyhow::anyhow!(
64 "No matching environments found (min score: {})",
65 min_score
66 ));
67 }
68
69 let _catalog_path = PathBuf::from(paths::framework::ROBOT_TASKS_CATALOG);
70 let base_path = PathBuf::from(paths::framework::ROBOT_TASKS_DIR);
71 let mut available_count = 0;
72
73 for env_match in &filtered_matches {
74 let env_path = base_path.join(&env_match.environment.path);
75 if env_path.exists() {
76 available_count += 1;
77 }
78 }
79
80 Ok(GenerationResult {
81 robot_scene: robot_output,
82 environments: filtered_matches.iter().map(|m| m.environment.id.clone()).collect(),
83 available_count,
84 })
85 }
86
87 pub fn generate_robot(&self, config_path: &Path, output_path: &Path) -> Result<()> {
94 let robot_generator = RobotGenerator::from_config_file(config_path)?;
95 robot_generator.generate(output_path)
96 }
97
98 pub fn list_environments(&self, config_path: &Path, verbose: bool) -> Result<Vec<EnvironmentInfo>> {
105 let profile = RobotProfile::from_config_file(config_path)?;
106 let selector = EnvironmentSelector::new()?;
107 let matches = selector.select_environments(&profile, 100)?;
108
109 let base_path = PathBuf::from(paths::framework::ROBOT_TASKS_DIR);
110 let mut environments = Vec::new();
111
112 for env_match in matches {
113 let env_path = base_path.join(&env_match.environment.path);
114 let available = env_path.exists();
115
116 if verbose || available {
117 environments.push(EnvironmentInfo {
118 id: env_match.environment.id.clone(),
119 name: env_match.environment.name.clone(),
120 description: env_match.environment.description.clone(),
121 score: env_match.score,
122 available,
123 });
124 }
125 }
126
127 Ok(environments)
128 }
129
130 pub fn validate_config(&self, config_path: &Path) -> Result<ValidationResult> {
136 let profile = RobotProfile::from_config_file(config_path)?;
137
138 let mut errors = Vec::new();
139 let mut warnings = Vec::new();
140
141 if profile.platform.is_empty() {
142 errors.push("Platform not specified".to_string());
143 }
144
145 if profile.sensors.is_empty() {
146 warnings.push("No sensors configured".to_string());
147 }
148
149 if profile.task_nodes.is_empty() {
150 warnings.push("No task nodes configured".to_string());
151 }
152
153 let is_valid = errors.is_empty();
154
155 Ok(ValidationResult {
156 is_valid,
157 errors,
158 warnings,
159 platform: profile.platform,
160 sensor_count: profile.sensors.len(),
161 node_count: profile.task_nodes.len(),
162 })
163 }
164
165 pub fn is_setup(&self) -> bool {
167 self.base_path.exists() && self.base_path.join("robot.tscn").exists()
168 }
169
170 pub fn base_path(&self) -> &Path {
172 &self.base_path
173 }
174}
175
176impl Default for SimulationService {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182#[derive(Debug)]
183pub struct GenerationResult {
184 pub robot_scene: PathBuf,
185 pub environments: Vec<String>,
186 pub available_count: usize,
187}
188
189#[derive(Debug, Clone)]
190pub struct EnvironmentInfo {
191 pub id: String,
192 pub name: String,
193 pub description: String,
194 pub score: i32,
195 pub available: bool,
196}
197
198#[derive(Debug)]
199pub struct ValidationResult {
200 pub is_valid: bool,
201 pub errors: Vec<String>,
202 pub warnings: Vec<String>,
203 pub platform: String,
204 pub sensor_count: usize,
205 pub node_count: usize,
206}