Loading...
Searching...
No Matches
SO3StateSpace.cpp
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2010, Rice University
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Rice University nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Mark Moll, Ioan Sucan */
36
37#include "ompl/base/spaces/SO3StateSpace.h"
38#include <algorithm>
39#include <limits>
40#include <cmath>
41#include "ompl/tools/config/MagicConstants.h"
42#include <boost/math/constants/constants.hpp>
43#include <boost/assert.hpp>
44
45using namespace boost::math::double_constants;
46
47static const double MAX_QUATERNION_NORM_ERROR = 1e-9;
48
50namespace ompl
51{
52 namespace base
53 {
54 static inline void computeAxisAngle(SO3StateSpace::StateType &q, double ax, double ay, double az, double angle)
55 {
56 double norm = std::sqrt(ax * ax + ay * ay + az * az);
57 if (norm < MAX_QUATERNION_NORM_ERROR)
58 q.setIdentity();
59 else
60 {
61 double half_angle = angle / 2.0;
62 double s = sin(half_angle) / norm;
63 q.x = s * ax;
64 q.y = s * ay;
65 q.z = s * az;
66 q.w = cos(half_angle);
67 }
68 }
69
70 /* Standard quaternion multiplication: q = q0 * q1 */
71 static inline void quaternionProduct(SO3StateSpace::StateType &q, const SO3StateSpace::StateType &q0,
73 {
74 q.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
75 q.y = q0.w * q1.y + q0.y * q1.w + q0.z * q1.x - q0.x * q1.z;
76 q.z = q0.w * q1.z + q0.z * q1.w + q0.x * q1.y - q0.y * q1.x;
77 q.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
78 }
79
80 inline double quaternionNormSquared(const SO3StateSpace::StateType &q)
81 {
82 return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
83 }
84 } // namespace base
85} // namespace ompl
87
88void ompl::base::SO3StateSpace::StateType::setAxisAngle(double ax, double ay, double az, double angle)
89{
90 computeAxisAngle(*this, ax, ay, az, angle);
91}
92
94{
95 x = y = z = 0.0;
96 w = 1.0;
97}
98
100{
101 rng_.quaternion(&state->as<SO3StateSpace::StateType>()->x);
102}
103
105{
106 if (distance >= .25 * pi)
107 {
108 sampleUniform(state);
109 return;
110 }
111 double d = rng_.uniform01();
112 SO3StateSpace::StateType q, *qs = static_cast<SO3StateSpace::StateType *>(state);
113 const auto *qnear = static_cast<const SO3StateSpace::StateType *>(near);
114 computeAxisAngle(q, rng_.gaussian01(), rng_.gaussian01(), rng_.gaussian01(), 2. * pow(d, third) * distance);
115 quaternionProduct(*qs, *qnear, q);
116}
117
118void ompl::base::SO3StateSampler::sampleGaussian(State *state, const State *mean, const double stdDev)
119{
120 // The standard deviation of the individual components of the tangent
121 // perturbation needs to be scaled so that the expected quaternion distance
122 // between the sampled state and the mean state is stdDev. The factor 2 is
123 // due to the way we define distance (see also Matt Mason's lecture notes
124 // on quaternions at
125 // http://www.cs.cmu.edu/afs/cs/academic/class/16741-s07/www/lectures/Lecture8.pdf).
126 // The 1/sqrt(3) factor is necessary because the distribution in the tangent
127 // space is a 3-dimensional Gaussian, so that the *length* of a tangent
128 // vector needs to be scaled by 1/sqrt(3).
129 double rotDev = (2. * stdDev) / root_three;
130
131 // CDF of N(0, 1.17) at -pi/4 is approx. .25, so there's .25 probability
132 // weight in each tail. Since the maximum distance in SO(3) is pi/2, we're
133 // essentially as likely to sample a state within distance [0, pi/4] as
134 // within distance [pi/4, pi/2]. With most weight in the tails (that wrap
135 // around in case of quaternions) we might as well sample uniformly.
136 if (rotDev > 1.17)
137 {
138 sampleUniform(state);
139 return;
140 }
141
142 double x = rng_.gaussian(0, rotDev), y = rng_.gaussian(0, rotDev), z = rng_.gaussian(0, rotDev),
143 theta = std::sqrt(x * x + y * y + z * z);
144 if (theta < std::numeric_limits<double>::epsilon())
145 space_->copyState(state, mean);
146 else
147 {
148 SO3StateSpace::StateType q, *qs = static_cast<SO3StateSpace::StateType *>(state);
149 const auto *qmu = static_cast<const SO3StateSpace::StateType *>(mean);
150 double half_theta = theta / 2.0;
151 double s = sin(half_theta) / theta;
152 q.w = cos(half_theta);
153 q.x = s * x;
154 q.y = s * y;
155 q.z = s * z;
156 quaternionProduct(*qs, *qmu, q);
157 }
158}
159
161{
162 return 3;
163}
164
166{
167 return .5 * pi;
168}
169
171{
172 // half of the surface area of a unit 3-sphere
173 return pi * pi;
174}
175
177{
178 double nrmSqr = quaternionNormSquared(*state);
179 return (fabs(nrmSqr - 1.0) > std::numeric_limits<double>::epsilon()) ? std::sqrt(nrmSqr) : 1.0;
180}
181
183{
184 // see http://stackoverflow.com/questions/11667783/quaternion-and-normalization/12934750#12934750
185 auto *qstate = static_cast<StateType *>(state);
186 double nrmsq = quaternionNormSquared(*qstate);
187 double error = std::abs(1.0 - nrmsq);
188 const double epsilon = 2.107342e-08;
189 if (error < epsilon)
190 {
191 double scale = 2.0 / (1.0 + nrmsq);
192 qstate->x *= scale;
193 qstate->y *= scale;
194 qstate->z *= scale;
195 qstate->w *= scale;
196 }
197 else
198 {
199 if (nrmsq < 1e-6)
200 qstate->setIdentity();
201 else
202 {
203 double scale = 1.0 / std::sqrt(nrmsq);
204 qstate->x *= scale;
205 qstate->y *= scale;
206 qstate->z *= scale;
207 qstate->w *= scale;
208 }
209 }
210}
211
213{
214 return fabs(norm(static_cast<const StateType *>(state)) - 1.0) < MAX_QUATERNION_NORM_ERROR;
215}
216
217void ompl::base::SO3StateSpace::copyState(State *destination, const State *source) const
218{
219 const auto *qsource = static_cast<const StateType *>(source);
220 auto *qdestination = static_cast<StateType *>(destination);
221 qdestination->x = qsource->x;
222 qdestination->y = qsource->y;
223 qdestination->z = qsource->z;
224 qdestination->w = qsource->w;
225}
226
228{
229 return sizeof(double) * 4;
230}
231
232void ompl::base::SO3StateSpace::serialize(void *serialization, const State *state) const
233{
234 memcpy(serialization, &state->as<StateType>()->x, sizeof(double) * 4);
235}
236
237void ompl::base::SO3StateSpace::deserialize(State *state, const void *serialization) const
238{
239 memcpy(&state->as<StateType>()->x, serialization, sizeof(double) * 4);
240}
241
243
244/*
245Based on code from :
246
247Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
248*/
249namespace ompl
250{
251 namespace base
252 {
253 static inline double arcLength(const State *state1, const State *state2)
254 {
255 const auto *qs1 = static_cast<const SO3StateSpace::StateType *>(state1);
256 const auto *qs2 = static_cast<const SO3StateSpace::StateType *>(state2);
257 double dq = fabs(qs1->x * qs2->x + qs1->y * qs2->y + qs1->z * qs2->z + qs1->w * qs2->w);
258 if (dq > 1.0 - MAX_QUATERNION_NORM_ERROR)
259 return 0.0;
260 return acos(dq);
261 }
262 } // namespace base
263} // namespace ompl
265
266double ompl::base::SO3StateSpace::distance(const State *state1, const State *state2) const
267{
268 BOOST_ASSERT_MSG(satisfiesBounds(state1) && satisfiesBounds(state2), "The states passed to SO3StateSpace::distance "
269 "are not within bounds. Call "
270 "SO3StateSpace::enforceBounds() in, e.g., "
271 "ompl::control::ODESolver::"
272 "PostPropagationEvent, "
273 "ompl::control::StatePropagator, or "
274 "ompl::base::StateValidityChecker");
275 return arcLength(state1, state2);
276}
277
278bool ompl::base::SO3StateSpace::equalStates(const State *state1, const State *state2) const
279{
280 return arcLength(state1, state2) < std::numeric_limits<double>::epsilon();
281}
282
283/*
284Based on code from :
285
286Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
287*/
288void ompl::base::SO3StateSpace::interpolate(const State *from, const State *to, const double t, State *state) const
289{
290 assert(fabs(norm(static_cast<const StateType *>(from)) - 1.0) < MAX_QUATERNION_NORM_ERROR);
291 assert(fabs(norm(static_cast<const StateType *>(to)) - 1.0) < MAX_QUATERNION_NORM_ERROR);
292
293 double theta = arcLength(from, to);
294 if (theta > std::numeric_limits<double>::epsilon())
295 {
296 double d = 1.0 / sin(theta);
297 double s0 = sin((1.0 - t) * theta);
298 double s1 = sin(t * theta);
299
300 const auto *qs1 = static_cast<const StateType *>(from);
301 const auto *qs2 = static_cast<const StateType *>(to);
302 auto *qr = static_cast<StateType *>(state);
303 double dq = qs1->x * qs2->x + qs1->y * qs2->y + qs1->z * qs2->z + qs1->w * qs2->w;
304 if (dq < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp
305 s1 = -s1;
306
307 qr->x = (qs1->x * s0 + qs2->x * s1) * d;
308 qr->y = (qs1->y * s0 + qs2->y * s1) * d;
309 qr->z = (qs1->z * s0 + qs2->z * s1) * d;
310 qr->w = (qs1->w * s0 + qs2->w * s1) * d;
311 }
312 else
313 {
314 if (state != from)
315 copyState(state, from);
316 }
317}
318
320{
321 return std::make_shared<SO3StateSampler>(this);
322}
323
328
330{
331 delete static_cast<StateType *>(state);
332}
333
335{
336 class SO3DefaultProjection : public ProjectionEvaluator
337 {
338 public:
339 SO3DefaultProjection(const StateSpace *space) : ProjectionEvaluator(space)
340 {
341 }
342
343 unsigned int getDimension() const override
344 {
345 return 3;
346 }
347
348 void defaultCellSizes() override
349 {
350 cellSizes_.resize(3);
351 cellSizes_[0] = pi / magic::PROJECTION_DIMENSION_SPLITS;
352 cellSizes_[1] = pi / magic::PROJECTION_DIMENSION_SPLITS;
353 cellSizes_[2] = pi / magic::PROJECTION_DIMENSION_SPLITS;
354 bounds_.resize(3);
355 bounds_.setLow(-1.0);
356 bounds_.setHigh(1.0);
357 }
358
359 void project(const State *state, Eigen::Ref<Eigen::VectorXd> projection) const override
360 {
361 projection(0) = state->as<SO3StateSpace::StateType>()->x;
362 projection(1) = state->as<SO3StateSpace::StateType>()->y;
363 projection(2) = state->as<SO3StateSpace::StateType>()->z;
364 }
365 };
366
367 registerDefaultProjection(std::make_shared<SO3DefaultProjection>(this));
368}
369
370double *ompl::base::SO3StateSpace::getValueAddressAtIndex(State *state, const unsigned int index) const
371{
372 return index < 4 ? &(state->as<StateType>()->x) + index : nullptr;
373}
374
375void ompl::base::SO3StateSpace::printState(const State *state, std::ostream &out) const
376{
377 out << "SO3State [";
378 if (state != nullptr)
379 {
380 const auto *qstate = static_cast<const StateType *>(state);
381 out << qstate->x << " " << qstate->y << " " << qstate->z << " " << qstate->w;
382 }
383 else
384 out << "nullptr";
385 out << ']' << std::endl;
386}
387
388void ompl::base::SO3StateSpace::printSettings(std::ostream &out) const
389{
390 out << "SO(3) state space '" << getName() << "' (represented using quaternions)" << std::endl;
391}
Abstract definition for a class computing projections to Rn. Implicit integer grids are imposed on th...
void sampleGaussian(State *state, const State *mean, double stdDev) override
Sample a state such that the expected distance between mean and state is stdDev.
void sampleUniformNear(State *state, const State *near, double distance) override
To sample unit quaternions uniformly within some given distance, we sample a 3-vector from the R^3 ta...
void sampleUniform(State *state) override
Sample a state.
The definition of a state in SO(3) represented as a unit quaternion.
double x
X component of quaternion vector.
double w
scalar component of quaternion
double z
Z component of quaternion vector.
void setIdentity()
Set the state to identity – no rotation.
double y
Y component of quaternion vector.
void setAxisAngle(double ax, double ay, double az, double angle)
Set the quaternion from axis-angle representation. The angle is given in radians.
void copyState(State *destination, const State *source) const override
Copy a state to another. The memory of source and destination should NOT overlap.
unsigned int getSerializationLength() const override
Get the number of chars in the serialization of a state in this space.
State * allocState() const override
Allocate a state that can store a point in the described space.
double norm(const StateType *state) const
Compute the norm of a state.
void printSettings(std::ostream &out) const override
Print the settings for this state space to a stream.
StateSamplerPtr allocDefaultStateSampler() const override
Allocate an instance of the default uniform state sampler for this space.
void registerProjections() override
Register the projections for this state space. Usually, this is at least the default projection....
double distance(const State *state1, const State *state2) const override
Computes distance between two states. This function satisfies the properties of a metric if isMetricS...
void serialize(void *serialization, const State *state) const override
Write the binary representation of state to serialization.
unsigned int getDimension() const override
Get the dimension of the space (not the dimension of the surrounding ambient space).
bool equalStates(const State *state1, const State *state2) const override
Checks whether two states are equal.
double * getValueAddressAtIndex(State *state, unsigned int index) const override
Many states contain a number of double values. This function provides a means to get the memory addre...
double getMaximumExtent() const override
Get the maximum value a call to distance() can return (or an upper bound). For unbounded state spaces...
void printState(const State *state, std::ostream &out) const override
Print a state to a stream.
void enforceBounds(State *state) const override
Bring the state within the bounds of the state space. For unbounded spaces this function can be a no-...
double getMeasure() const override
Get a measure of the space (this can be thought of as a generalization of volume).
void deserialize(State *state, const void *serialization) const override
Read the binary representation of a state from serialization and write it to state.
void freeState(State *state) const override
Free the memory of the allocated state.
void interpolate(const State *from, const State *to, double t, State *state) const override
Computes the state that lies at time t in [0, 1] on the segment that connects from state to to state....
bool satisfiesBounds(const State *state) const override
Check if a state is inside the bounding box. For unbounded spaces this function can always return tru...
RNG rng_
An instance of a random number generator.
const StateSpace * space_
The state space this sampler samples.
void registerDefaultProjection(const ProjectionEvaluatorPtr &projection)
Register the default projection for this state space.
const std::string & getName() const
Get the name of the state space.
Definition of an abstract state.
Definition State.h:50
const T * as() const
Cast this instance to a desired type.
Definition State.h:66
This namespace contains sampling based planning routines shared by both planning under geometric cons...
static const double PROJECTION_DIMENSION_SPLITS
When the cell sizes for a projection are automatically computed, this value defines the number of par...
Main namespace. Contains everything in this library.