Libbarrett
1.2.4
|
00001 /* 00002 Copyright 2009, 2010, 2011, 2012 Barrett Technology <support@barrett.com> 00003 00004 This file is part of libbarrett. 00005 00006 This version of libbarrett is free software: you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License as 00008 published by the Free Software Foundation, either version 3 of the 00009 License, or (at your option) any later version. 00010 00011 This version of libbarrett is distributed in the hope that it will be 00012 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License along 00017 with this version of libbarrett. If not, see 00018 <http://www.gnu.org/licenses/>. 00019 00020 Further, non-binding information about licensing is available at: 00021 <http://wiki.barrett.com/libbarrett/wiki/LicenseNotes> 00022 */ 00023 00024 /* 00025 * spline-inl.h 00026 * 00027 * Created on: Dec 22, 2009 00028 * Author: dc 00029 */ 00030 00031 00032 #include <iostream> 00033 #include <cassert> 00034 00035 #include <gsl/gsl_interp.h> 00036 00037 #include <barrett/math/utils.h> 00038 #include <barrett/cdlbt/spline.h> 00039 00040 00041 namespace barrett { 00042 namespace math { 00043 00044 00045 template<typename T> 00046 template<template<typename, typename> class Container, typename Allocator> 00047 Spline<T>::Spline(const Container<tuple_type, Allocator>& samples, bool saturateS) : 00048 impl(NULL), sat(saturateS), s_0(0.0), s_f(0.0) 00049 { 00050 s_0 = boost::get<0>(samples[0]); 00051 00052 bt_spline_create(&impl, boost::get<1>(samples[0]).asGslType(), BT_SPLINE_MODE_EXTERNAL); 00053 00054 typename Container<tuple_type, Allocator>::const_iterator i; 00055 for (i = ++(samples.begin()); i != samples.end(); ++i) { // start with the 2nd sample 00056 bt_spline_add(impl, boost::get<1>(*i).asGslType(), boost::get<0>(*i) - s_0); 00057 } 00058 00059 bt_spline_init(impl, NULL, NULL); 00060 s_f = s_0 + changeInS(); 00061 } 00062 00063 template<typename T> 00064 template<template<typename, typename> class Container, typename Allocator> 00065 Spline<T>::Spline(const Container<T, Allocator>& points, /*const typename T::unitless_type& initialDirection,*/ bool saturateS) : 00066 impl(NULL), sat(saturateS), s_0(0.0), s_f(0.0) 00067 { 00068 bt_spline_create(&impl, points[0].asGslType(), BT_SPLINE_MODE_ARCLEN); 00069 00070 typename Container<T, Allocator>::const_iterator i; 00071 for (i = ++(points.begin()); i != points.end(); ++i) { // start with the 2nd sample 00072 bt_spline_add(impl, (*i).asGslType(), 0); 00073 } 00074 00075 /* 00076 // local copy because init modifies its 3rd parameter 00077 typename T::unitless_type id(initialDirection); 00078 bt_spline_init(impl, NULL, id.asGslType()); 00079 */ 00080 bt_spline_init(impl, NULL, NULL); 00081 00082 s_f = s_0 + changeInS(); 00083 } 00084 00085 template<typename T> 00086 Spline<T>::~Spline() 00087 { 00088 bt_spline_destroy(impl); 00089 impl = NULL; 00090 } 00091 00092 template<typename T> 00093 inline double Spline<T>::changeInS() const 00094 { 00095 return impl->length; 00096 } 00097 00098 template<typename T> 00099 inline T Spline<T>::eval(double s) const 00100 { 00101 if (sat) { 00102 s = saturate(s, s_0, s_f); 00103 } 00104 00105 T result; 00106 bt_spline_get(impl, result.asGslType(), s - s_0); 00107 return result; 00108 } 00109 00110 template<typename T> 00111 inline T Spline<T>::evalDerivative(double s) const 00112 { 00113 if (sat) { 00114 s = saturate(s, s_0, s_f); 00115 } 00116 00117 T result; 00118 for (int i = 0; i < impl->dimension; ++i) { 00119 result[i] = gsl_interp_eval_deriv(impl->interps[i], impl->ss, impl->points[i], s - s_0, impl->acc); 00120 } 00121 return result; 00122 } 00123 00124 00125 // Specialization for Eigen::Quaternion types 00126 template<typename Scalar> 00127 template<template<typename, typename> class Container, typename Allocator> 00128 Spline<Eigen::Quaternion<Scalar> >::Spline(const Container<tuple_type, Allocator>& samples, bool saturateS) : 00129 data(samples.begin(), samples.end()), sat(saturateS), index(0), rate(-1.0) 00130 { 00131 // Make sure s is monotonic. 00132 for (size_t i = 0; i < data.size() - 1; ++i) { 00133 assert(boost::get<0>(data[i]) < boost::get<0>(data[i+1])); 00134 } 00135 } 00136 00137 template<typename Scalar> 00138 template<template<typename, typename> class Container, typename Allocator> 00139 Spline<Eigen::Quaternion<Scalar> >::Spline(const Container<data_type, Allocator>& points, bool saturateS) : 00140 data(points.size()), sat(saturateS), index(0), rate(-1.0) 00141 { 00142 double s = 0.0; 00143 for (size_t i = 0; i < data.size(); ++i) { 00144 if (i > 0) { 00145 double ad = points.at(i).angularDistance(points.at(i-1)); 00146 assert(ad >= 0.0); 00147 00148 // If the points are too close together, enforce an artificial 00149 // minimum distance. This keeps division by delta-s under control. 00150 s += math::max(ad, 1e-4); 00151 } 00152 00153 boost::get<0>(data[i]) = s; 00154 boost::get<1>(data[i]) = points.at(i); 00155 } 00156 00157 // Make sure s is monotonic. 00158 for (size_t i = 0; i < data.size() - 1; ++i) { 00159 assert(boost::get<0>(data[i]) < boost::get<0>(data[i+1])); 00160 } 00161 } 00162 00163 template<typename Scalar> 00164 typename Spline<Eigen::Quaternion<Scalar> >::data_type Spline<Eigen::Quaternion<Scalar> >::eval(double s) const 00165 { 00166 s = saturate(s, initialS(), finalS()); 00167 00168 while (index > 0 && s < boost::get<0>(data[index])) { 00169 --index; 00170 rate = -1.0; 00171 } 00172 while (index < data.size()-1 && s >= boost::get<0>(data[index+1])) { 00173 ++index; 00174 rate = -1.0; 00175 } 00176 assert(index < data.size()); 00177 00178 if (index == data.size()-1) { 00179 return boost::get<1>(data[index]); 00180 } else { 00181 if (rate < 0.0) { 00182 rate = 1.0 / (boost::get<0>(data[index+1]) - boost::get<0>(data[index])); 00183 } 00184 00185 return boost::get<1>(data[index]).slerp(rate * (s - boost::get<0>(data[index])), boost::get<1>(data[index+1])); 00186 } 00187 } 00188 00189 00190 } 00191 }