1use crate::base::{
6 goal::JsGoal,
7 path::JsPath,
8 planner::JsPlannerConfig,
9 problem_definition::{JsProblemDefinition, ProblemDefinitionVariant},
10 state_validity_checker::JsStateValidityChecker,
11};
12use oxmpl::base::{
13 planner::Planner,
14 space::{
15 CompoundStateSpace, RealVectorStateSpace, SE2StateSpace, SE3StateSpace, SO2StateSpace,
16 SO3StateSpace,
17 },
18 state::{CompoundState, RealVectorState, SE2State, SE3State, SO2State, SO3State},
19};
20use oxmpl::geometric::PRM;
21use std::sync::Arc;
22use std::time::Duration;
23use wasm_bindgen::prelude::*;
24
25enum PRMVariant {
26 RealVector(PRM<RealVectorState, RealVectorStateSpace, JsGoal>),
27 SO2(PRM<SO2State, SO2StateSpace, JsGoal>),
28 SO3(PRM<SO3State, SO3StateSpace, JsGoal>),
29 Compound(PRM<CompoundState, CompoundStateSpace, JsGoal>),
30 SE2(PRM<SE2State, SE2StateSpace, JsGoal>),
31 SE3(PRM<SE3State, SE3StateSpace, JsGoal>),
32}
33
34#[wasm_bindgen(js_name = PRM)]
35pub struct JsPRM {
36 planner: PRMVariant,
37 pd: ProblemDefinitionVariant,
38}
39
40#[wasm_bindgen(js_class = PRM)]
41impl JsPRM {
42 #[wasm_bindgen(constructor)]
43 pub fn new(
44 timeout_secs: f32,
45 connection_radius: f64,
46 problem_def: &JsProblemDefinition,
47 config: &JsPlannerConfig,
48 ) -> Self {
49 let planner_config = config.into();
50 match &problem_def.inner {
51 ProblemDefinitionVariant::RealVector(pd) => Self {
52 planner: PRMVariant::RealVector(PRM::new(
53 timeout_secs.into(),
54 connection_radius,
55 &planner_config,
56 )),
57 pd: ProblemDefinitionVariant::RealVector(pd.clone()),
58 },
59 ProblemDefinitionVariant::SO2(pd) => Self {
60 planner: PRMVariant::SO2(PRM::new(
61 timeout_secs.into(),
62 connection_radius,
63 &planner_config,
64 )),
65 pd: ProblemDefinitionVariant::SO2(pd.clone()),
66 },
67 ProblemDefinitionVariant::SO3(pd) => Self {
68 planner: PRMVariant::SO3(PRM::new(
69 timeout_secs.into(),
70 connection_radius,
71 &planner_config,
72 )),
73 pd: ProblemDefinitionVariant::SO3(pd.clone()),
74 },
75 ProblemDefinitionVariant::Compound(pd) => Self {
76 planner: PRMVariant::Compound(PRM::new(
77 timeout_secs.into(),
78 connection_radius,
79 &planner_config,
80 )),
81 pd: ProblemDefinitionVariant::Compound(pd.clone()),
82 },
83 ProblemDefinitionVariant::SE2(pd) => Self {
84 planner: PRMVariant::SE2(PRM::new(
85 timeout_secs.into(),
86 connection_radius,
87 &planner_config,
88 )),
89 pd: ProblemDefinitionVariant::SE2(pd.clone()),
90 },
91 ProblemDefinitionVariant::SE3(pd) => Self {
92 planner: PRMVariant::SE3(PRM::new(
93 timeout_secs.into(),
94 connection_radius,
95 &planner_config,
96 )),
97 pd: ProblemDefinitionVariant::SE3(pd.clone()),
98 },
99 }
100 }
101
102 pub fn setup(&mut self, validity_checker: &JsStateValidityChecker) {
103 let checker = Arc::new(validity_checker.clone());
104 match &mut self.planner {
105 PRMVariant::RealVector(p) => {
106 if let ProblemDefinitionVariant::RealVector(pd) = &self.pd {
107 p.setup(pd.clone(), checker);
108 }
109 }
110 PRMVariant::SO2(p) => {
111 if let ProblemDefinitionVariant::SO2(pd) = &self.pd {
112 p.setup(pd.clone(), checker);
113 }
114 }
115 PRMVariant::SO3(p) => {
116 if let ProblemDefinitionVariant::SO3(pd) = &self.pd {
117 p.setup(pd.clone(), checker);
118 }
119 }
120 PRMVariant::Compound(p) => {
121 if let ProblemDefinitionVariant::Compound(pd) = &self.pd {
122 p.setup(pd.clone(), checker);
123 }
124 }
125 PRMVariant::SE2(p) => {
126 if let ProblemDefinitionVariant::SE2(pd) = &self.pd {
127 p.setup(pd.clone(), checker);
128 }
129 }
130 PRMVariant::SE3(p) => {
131 if let ProblemDefinitionVariant::SE3(pd) = &self.pd {
132 p.setup(pd.clone(), checker);
133 }
134 }
135 }
136 }
137
138 #[wasm_bindgen(js_name = constructRoadmap)]
139 pub fn construct_roadmap(&mut self) -> Result<(), String> {
140 match &mut self.planner {
141 PRMVariant::RealVector(p) => p.construct_roadmap().map_err(|e| e.to_string()),
142 PRMVariant::SO2(p) => p.construct_roadmap().map_err(|e| e.to_string()),
143 PRMVariant::SO3(p) => p.construct_roadmap().map_err(|e| e.to_string()),
144 PRMVariant::Compound(p) => p.construct_roadmap().map_err(|e| e.to_string()),
145 PRMVariant::SE2(p) => p.construct_roadmap().map_err(|e| e.to_string()),
146 PRMVariant::SE3(p) => p.construct_roadmap().map_err(|e| e.to_string()),
147 }
148 }
149
150 pub fn solve(&mut self, timeout_secs: f32) -> Result<JsPath, String> {
151 let timeout = Duration::from_secs_f32(timeout_secs);
152 match &mut self.planner {
153 PRMVariant::RealVector(p) => p
154 .solve(timeout)
155 .map(JsPath::from)
156 .map_err(|e| e.to_string()),
157 PRMVariant::SO2(p) => p
158 .solve(timeout)
159 .map(JsPath::from)
160 .map_err(|e| e.to_string()),
161 PRMVariant::SO3(p) => p
162 .solve(timeout)
163 .map(JsPath::from)
164 .map_err(|e| e.to_string()),
165 PRMVariant::Compound(p) => p
166 .solve(timeout)
167 .map(JsPath::from)
168 .map_err(|e| e.to_string()),
169 PRMVariant::SE2(p) => p
170 .solve(timeout)
171 .map(JsPath::from)
172 .map_err(|e| e.to_string()),
173 PRMVariant::SE3(p) => p
174 .solve(timeout)
175 .map(JsPath::from)
176 .map_err(|e| e.to_string()),
177 }
178 }
179}