1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2025 Junior Sundar
//
// SPDX-License-Identifier: BSD-3-Clause
use Rng;
pub use crate;
use crate;
/// Defines a space in which planning can be performed.
///
/// A `StateSpace` represents the manifold where states exist. It defines the properties and
/// operations applicable to that space as a whole, such as how to measure distance, how to
/// interpolate between states, and how to generate new states.
///
/// This trait is generic and can be implemented for various types of spaces, like N-dimensional
/// Euclidean vectors (`RealVectorStateSpace`) or 2D rotations (`SO2StateSpace`). Planners are
/// written to be generic over this trait, allowing them to solve problems in any space that
/// implements these fundamental operations.
///
/// # Examples
///
/// ```
/// use std::f64;
/// use oxmpl::base::state::State;
/// use oxmpl::base::space::StateSpace;
/// use oxmpl::base::error::StateSamplingError;
/// use rand::Rng;
///
/// #[derive(Debug, Clone, PartialEq)]
/// struct Point1D {
/// x: f64,
/// }
/// impl State for Point1D {}
///
/// struct LineSegmentSpace {
/// bounds: (f64, f64),
/// }
///
/// impl StateSpace for LineSegmentSpace {
/// type StateType = Point1D;
///
/// fn distance(&self, state1: &Self::StateType, state2: &Self::StateType) -> f64 {
/// (state1.x - state2.x).abs()
/// }
///
/// fn interpolate(&self, from: &Self::StateType, to: &Self::StateType, t: f64, state: &mut Self::StateType) {
/// state.x = from.x + (to.x - from.x) * t;
/// }
///
/// fn enforce_bounds(&self, state: &mut Self::StateType) {
/// state.x = state.x.clamp(self.bounds.0, self.bounds.1);
/// }
///
/// fn satisfies_bounds(&self, state: &Self::StateType) -> bool {
/// state.x >= self.bounds.0 && state.x <= self.bounds.1
/// }
///
/// fn sample_uniform(&self, rng: &mut impl Rng) -> Result<Self::StateType, StateSamplingError> {
/// Ok(Point1D { x: rng.gen_range(self.bounds.0..self.bounds.1) })
/// }
/// }
///
/// let space = LineSegmentSpace { bounds: (0.0, 10.0) };
/// let mut rng = rand::thread_rng();
/// let random_state = space.sample_uniform(&mut rng).unwrap();
///
/// assert!(space.satisfies_bounds(&random_state));
/// ```