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(
47 &self,
48 config_path: &Path,
49 output_path: &Path,
50 robot_tasks_dir: &Path,
51 max_envs: usize,
52 min_score: i32,
53 ) -> Result<GenerationResult> {
54 let profile = RobotProfile::from_config_file(config_path)?;
55
56 let robot_output = output_path.join("robot.tscn");
57 let robot_generator = RobotGenerator::from_config_file(config_path)?;
58 robot_generator.generate(&robot_output)?;
59
60 let selector = EnvironmentSelector::new(robot_tasks_dir)?;
61 let matches = selector.select_environments(&profile, max_envs)?;
62
63 let filtered_matches: Vec<_> = matches.into_iter().filter(|m| m.score >= min_score).collect();
64
65 if filtered_matches.is_empty() {
66 return Err(anyhow::anyhow!(
67 "No matching environments found (min score: {})",
68 min_score
69 ));
70 }
71
72 let base_path = robot_tasks_dir;
73 let mut available_count = 0;
74
75 for env_match in &filtered_matches {
76 let env_path = base_path.join(&env_match.environment.path);
77 if env_path.exists() {
78 available_count += 1;
79 }
80 }
81
82 Ok(GenerationResult {
83 robot_scene: robot_output,
84 environments: filtered_matches.iter().map(|m| m.environment.id.clone()).collect(),
85 available_count,
86 })
87 }
88
89 pub fn generate_robot(&self, config_path: &Path, output_path: &Path) -> Result<()> {
96 let robot_generator = RobotGenerator::from_config_file(config_path)?;
97 robot_generator.generate(output_path)
98 }
99
100 pub fn list_environments(
109 &self,
110 config_path: &Path,
111 robot_tasks_dir: &Path,
112 verbose: bool,
113 ) -> Result<Vec<EnvironmentInfo>> {
114 let profile = RobotProfile::from_config_file(config_path)?;
115 let selector = EnvironmentSelector::new(robot_tasks_dir)?;
116 let matches = selector.select_environments(&profile, 100)?;
117
118 let base_path = robot_tasks_dir;
119 let mut environments = Vec::new();
120
121 for env_match in matches {
122 let env_path = base_path.join(&env_match.environment.path);
123 let available = env_path.exists();
124
125 if verbose || available {
126 environments.push(EnvironmentInfo {
127 id: env_match.environment.id.clone(),
128 name: env_match.environment.name.clone(),
129 description: env_match.environment.description.clone(),
130 score: env_match.score,
131 available,
132 });
133 }
134 }
135
136 Ok(environments)
137 }
138
139 pub fn validate_config(&self, config_path: &Path) -> Result<ValidationResult> {
145 let profile = RobotProfile::from_config_file(config_path)?;
146
147 let mut errors = Vec::new();
148 let mut warnings = Vec::new();
149
150 if profile.platform.is_empty() {
151 errors.push("Platform not specified".to_string());
152 }
153
154 if profile.sensors.is_empty() {
155 warnings.push("No sensors configured".to_string());
156 }
157
158 if profile.task_nodes.is_empty() {
159 warnings.push("No task nodes configured".to_string());
160 }
161
162 let is_valid = errors.is_empty();
163
164 Ok(ValidationResult {
165 is_valid,
166 errors,
167 warnings,
168 platform: profile.platform,
169 sensor_count: profile.sensors.len(),
170 node_count: profile.task_nodes.len(),
171 })
172 }
173
174 pub fn is_setup(&self) -> bool {
176 self.base_path.exists() && self.base_path.join("robot.tscn").exists()
177 }
178
179 pub fn base_path(&self) -> &Path {
181 &self.base_path
182 }
183}
184
185impl Default for SimulationService {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191#[derive(Debug)]
192pub struct GenerationResult {
193 pub robot_scene: PathBuf,
194 pub environments: Vec<String>,
195 pub available_count: usize,
196}
197
198#[derive(Debug, Clone)]
199pub struct EnvironmentInfo {
200 pub id: String,
201 pub name: String,
202 pub description: String,
203 pub score: i32,
204 pub available: bool,
205}
206
207#[derive(Debug)]
208pub struct ValidationResult {
209 pub is_valid: bool,
210 pub errors: Vec<String>,
211 pub warnings: Vec<String>,
212 pub platform: String,
213 pub sensor_count: usize,
214 pub node_count: usize,
215}