Initial Commit (tested training, testing, and TRT conversion)
This commit is contained in:
168
flightlib/third_party/arc_utilities/include/arc_utilities/abb_irb1600_145_fk_fast.hpp
vendored
Normal file
168
flightlib/third_party/arc_utilities/include/arc_utilities/abb_irb1600_145_fk_fast.hpp
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <Eigen/Geometry>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef ABB_IRB1600_145_FK_FAST_HPP
|
||||
#define ABB_IRB1600_145_FK_FAST_HPP
|
||||
|
||||
namespace ABB_IRB1600_145_FK_FAST
|
||||
{
|
||||
const size_t ABB_IRB1600_145_NUM_ACTIVE_JOINTS = 6;
|
||||
const size_t ABB_IRB1600_145_NUM_LINKS = 8;
|
||||
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_1_NAME = "joint_1";
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_2_NAME = "joint_2";
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_3_NAME = "joint_3";
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_4_NAME = "joint_4";
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_5_NAME = "joint_5";
|
||||
const std::string ABB_IRB1600_145_ACTIVE_JOINT_6_NAME = "joint_6";
|
||||
|
||||
const std::string ABB_IRB1600_145_LINK_1_NAME = "link_0";
|
||||
const std::string ABB_IRB1600_145_LINK_2_NAME = "link_1";
|
||||
const std::string ABB_IRB1600_145_LINK_3_NAME = "link_2";
|
||||
const std::string ABB_IRB1600_145_LINK_4_NAME = "link_3";
|
||||
const std::string ABB_IRB1600_145_LINK_5_NAME = "link_4";
|
||||
const std::string ABB_IRB1600_145_LINK_6_NAME = "link_5";
|
||||
const std::string ABB_IRB1600_145_LINK_7_NAME = "link_6";
|
||||
const std::string ABB_IRB1600_145_LINK_8_NAME = "link_7";
|
||||
|
||||
typedef std::vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> VectorIsometry3d;
|
||||
|
||||
inline Eigen::Isometry3d Get_base_joint1_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.1245);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_1_joint_2_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.15, -0.1395, 0.362);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitY()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_2_joint_3_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.0, 0.028, 0.7);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitY()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_3_joint_4_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.314, 0.107, 0.0);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitX()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_4_joint_5_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.286, 0.0, 0.0);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitY()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_5_joint_6_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond pre_joint_rotation(1.0, 0.0, 0.0, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitX()));
|
||||
Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_Fixed_link_6_joint_tool_LinkJointTransform(void)
|
||||
{
|
||||
Eigen::Translation3d pre_joint_translation(0.065, 0.0, 0.0);
|
||||
Eigen::Quaterniond pre_joint_rotation(0.7071067811865476, 0.0, 0.7071067811865476, 0.0);
|
||||
Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
return pre_joint_transform;
|
||||
}
|
||||
|
||||
inline VectorIsometry3d GetLinkTransforms(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
assert(configuration.size() == ABB_IRB1600_145_NUM_ACTIVE_JOINTS);
|
||||
VectorIsometry3d link_transforms(ABB_IRB1600_145_NUM_LINKS);
|
||||
link_transforms[0] = base_transform;
|
||||
link_transforms[1] = link_transforms[0] * Get_base_joint1_LinkJointTransform(configuration[0]);
|
||||
link_transforms[2] = link_transforms[1] * Get_link_1_joint_2_LinkJointTransform(configuration[1]);
|
||||
link_transforms[3] = link_transforms[2] * Get_link_2_joint_3_LinkJointTransform(configuration[2]);
|
||||
link_transforms[4] = link_transforms[3] * Get_link_3_joint_4_LinkJointTransform(configuration[3]);
|
||||
link_transforms[5] = link_transforms[4] * Get_link_4_joint_5_LinkJointTransform(configuration[4]);
|
||||
link_transforms[6] = link_transforms[5] * Get_link_5_joint_6_LinkJointTransform(configuration[5]);
|
||||
link_transforms[7] = link_transforms[6] * Get_Fixed_link_6_joint_tool_LinkJointTransform();
|
||||
return link_transforms;
|
||||
}
|
||||
|
||||
inline VectorIsometry3d GetLinkTransforms(std::map<std::string, double> configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
std::vector<double> configuration_vector(ABB_IRB1600_145_NUM_ACTIVE_JOINTS);
|
||||
configuration_vector[0] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_1_NAME];
|
||||
configuration_vector[1] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_2_NAME];
|
||||
configuration_vector[2] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_3_NAME];
|
||||
configuration_vector[3] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_4_NAME];
|
||||
configuration_vector[4] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_5_NAME];
|
||||
configuration_vector[5] = configuration[ABB_IRB1600_145_ACTIVE_JOINT_6_NAME];
|
||||
return GetLinkTransforms(configuration_vector, base_transform);
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::map<std::string, double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[ABB_IRB1600_145_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ABB_IRB1600_145_FK_FAST_HPP
|
||||
229
flightlib/third_party/arc_utilities/include/arc_utilities/aligned_eigen_types.hpp
vendored
Normal file
229
flightlib/third_party/arc_utilities/include/arc_utilities/aligned_eigen_types.hpp
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef ALIGNED_EIGEN_TYPES_HPP
|
||||
#define ALIGNED_EIGEN_TYPES_HPP
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/**
|
||||
* \defgroup Aligned4Vector3_Module Aligned vector3 module
|
||||
*
|
||||
* \code
|
||||
* #include <unsupported/Eigen/Aligned4Vector3>
|
||||
* \endcode
|
||||
*/
|
||||
//@{
|
||||
|
||||
|
||||
/** \class Aligned4Vector3
|
||||
*
|
||||
* \brief A vectorization friendly 3D vector
|
||||
*
|
||||
* This class represents a 3D vector internally using a 4D vector
|
||||
* such that vectorization can be seamlessly enabled. Of course,
|
||||
* the same result can be achieved by directly using a 4D vector.
|
||||
* This class makes this process simpler.
|
||||
*
|
||||
*/
|
||||
// TODO specialize Cwise
|
||||
template<typename _Scalar> class Aligned4Vector3;
|
||||
|
||||
namespace internal {
|
||||
template<typename _Scalar> struct traits<Aligned4Vector3<_Scalar> >
|
||||
: traits<Matrix<_Scalar,3,1,0,3,1> >
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
template<typename _Scalar> class Aligned4Vector3
|
||||
: public MatrixBase<Aligned4Vector3<_Scalar> >
|
||||
{
|
||||
typedef Matrix<_Scalar,4,1> CoeffType;
|
||||
CoeffType m_coeffs;
|
||||
public:
|
||||
|
||||
typedef MatrixBase<Aligned4Vector3<_Scalar> > Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(Aligned4Vector3)
|
||||
using Base::operator*;
|
||||
|
||||
inline Index rows() const { return 3; }
|
||||
inline Index cols() const { return 1; }
|
||||
|
||||
Scalar* data() { return m_coeffs.data(); }
|
||||
const Scalar* data() const { return m_coeffs.data(); }
|
||||
Index innerStride() const { return 1; }
|
||||
Index outerStride() const { return m_coeffs.outerStride(); }
|
||||
|
||||
inline const Scalar& coeff(Index row, Index col) const
|
||||
{ return m_coeffs.coeff(row, col); }
|
||||
|
||||
inline Scalar& coeffRef(Index row, Index col)
|
||||
{ return m_coeffs.coeffRef(row, col); }
|
||||
|
||||
inline const Scalar& coeff(Index index) const
|
||||
{ return m_coeffs.coeff(index); }
|
||||
|
||||
inline Scalar& coeffRef(Index index)
|
||||
{ return m_coeffs.coeffRef(index);}
|
||||
|
||||
|
||||
inline Aligned4Vector3(const Scalar& x, const Scalar& y, const Scalar& z)
|
||||
: m_coeffs(x, y, z, Scalar(1))
|
||||
{}
|
||||
|
||||
inline Aligned4Vector3()
|
||||
: m_coeffs(Scalar(0), Scalar(0), Scalar(0), Scalar(1))
|
||||
{}
|
||||
|
||||
inline Aligned4Vector3(const Aligned4Vector3& other)
|
||||
: Base(), m_coeffs(other.m_coeffs)
|
||||
{}
|
||||
|
||||
template<typename XprType, int Size=XprType::SizeAtCompileTime>
|
||||
struct generic_assign_selector {};
|
||||
|
||||
template<typename XprType> struct generic_assign_selector<XprType,4>
|
||||
{
|
||||
inline static void run(Aligned4Vector3& dest, const XprType& src)
|
||||
{
|
||||
dest.m_coeffs = src;
|
||||
dest.m_coeffs.w() = Scalar(1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename XprType> struct generic_assign_selector<XprType,3>
|
||||
{
|
||||
inline static void run(Aligned4Vector3& dest, const XprType& src)
|
||||
{
|
||||
dest.m_coeffs.template head<3>() = src;
|
||||
dest.m_coeffs.w() = Scalar(1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
inline Aligned4Vector3(const MatrixBase<Derived>& other)
|
||||
{
|
||||
generic_assign_selector<Derived>::run(*this,other.derived());
|
||||
}
|
||||
|
||||
inline Aligned4Vector3& operator=(const Aligned4Vector3& other)
|
||||
{ m_coeffs = other.m_coeffs; return *this; }
|
||||
|
||||
template <typename Derived>
|
||||
inline Aligned4Vector3& operator=(const MatrixBase<Derived>& other)
|
||||
{
|
||||
generic_assign_selector<Derived>::run(*this,other.derived());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Aligned4Vector3 operator+(const Aligned4Vector3& other) const
|
||||
{return Aligned4Vector3(m_coeffs + other.m_coeffs); }
|
||||
|
||||
inline Aligned4Vector3& operator+=(const Aligned4Vector3& other)
|
||||
{ m_coeffs += other.m_coeffs; return *this; }
|
||||
|
||||
inline Aligned4Vector3 operator-(const Aligned4Vector3& other) const
|
||||
{ return Aligned4Vector3(m_coeffs - other.m_coeffs); }
|
||||
|
||||
inline Aligned4Vector3 operator-=(const Aligned4Vector3& other)
|
||||
{ m_coeffs -= other.m_coeffs; return *this; }
|
||||
|
||||
inline Aligned4Vector3 operator*(const Scalar& s) const
|
||||
{ return Aligned4Vector3(m_coeffs * s); }
|
||||
|
||||
inline friend Aligned4Vector3 operator*(const Scalar& s,const Aligned4Vector3& vec)
|
||||
{ return Aligned4Vector3(s * vec.m_coeffs); }
|
||||
|
||||
inline Aligned4Vector3& operator*=(const Scalar& s)
|
||||
{ m_coeffs *= s; return *this; }
|
||||
|
||||
inline Aligned4Vector3 operator/(const Scalar& s) const
|
||||
{ return Aligned4Vector3(m_coeffs / s); }
|
||||
|
||||
inline Aligned4Vector3& operator/=(const Scalar& s)
|
||||
{ m_coeffs /= s; return *this; }
|
||||
|
||||
inline Scalar dot(const Aligned4Vector3& other) const
|
||||
{
|
||||
eigen_assert(m_coeffs.w()==Scalar(1));
|
||||
eigen_assert(other.m_coeffs.w()==Scalar(1));
|
||||
return m_coeffs.dot(other.m_coeffs) - Scalar(1);
|
||||
}
|
||||
|
||||
inline void normalize()
|
||||
{
|
||||
m_coeffs /= norm();
|
||||
}
|
||||
|
||||
inline Aligned4Vector3 normalized() const
|
||||
{
|
||||
return Aligned4Vector3(m_coeffs / norm());
|
||||
}
|
||||
|
||||
inline Scalar sum() const
|
||||
{
|
||||
eigen_assert(m_coeffs.w()==Scalar(1));
|
||||
return m_coeffs.sum() - Scalar(1);
|
||||
}
|
||||
|
||||
inline Scalar squaredNorm() const
|
||||
{
|
||||
eigen_assert(m_coeffs.w()==Scalar(1));
|
||||
return m_coeffs.squaredNorm() - Scalar(1);
|
||||
}
|
||||
|
||||
inline Scalar norm() const
|
||||
{
|
||||
using std::sqrt;
|
||||
return sqrt(squaredNorm());
|
||||
}
|
||||
|
||||
inline Aligned4Vector3 cross(const Aligned4Vector3& other) const
|
||||
{
|
||||
return Aligned4Vector3(m_coeffs.cross3(other.m_coeffs));
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
inline bool isApprox(const MatrixBase<Derived>& other, RealScalar eps=NumTraits<Scalar>::dummy_precision()) const
|
||||
{
|
||||
return m_coeffs.template head<3>().isApprox(other,eps);
|
||||
}
|
||||
|
||||
CoeffType& coeffs() { return m_coeffs; }
|
||||
const CoeffType& coeffs() const { return m_coeffs; }
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename _Scalar>
|
||||
struct eval<Aligned4Vector3<_Scalar>, Dense>
|
||||
{
|
||||
typedef const Aligned4Vector3<_Scalar>& type;
|
||||
};
|
||||
|
||||
template<typename Scalar>
|
||||
struct evaluator<Aligned4Vector3<Scalar> >
|
||||
: evaluator<Matrix<Scalar,4,1> >
|
||||
{
|
||||
typedef Aligned4Vector3<Scalar> XprType;
|
||||
typedef evaluator<Matrix<Scalar,4,1> > Base;
|
||||
|
||||
evaluator(const XprType &m) : Base(m.coeffs()) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
}
|
||||
|
||||
#endif // ALIGNED_EIGEN_TYPES
|
||||
21
flightlib/third_party/arc_utilities/include/arc_utilities/arc_exceptions.hpp
vendored
Normal file
21
flightlib/third_party/arc_utilities/include/arc_utilities/arc_exceptions.hpp
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef ARC_EXCEPTIONS_HPP
|
||||
#define ARC_EXCEPTIONS_HPP
|
||||
|
||||
#define throw_arc_exception(type, ...) arc_exceptions::ArcException<type>(__FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
namespace arc_exceptions
|
||||
{
|
||||
template <typename ExceptionType>
|
||||
inline void ArcException(const char* file, const std::size_t line, const std::string& message)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << message << ": " << file << ": " << line;
|
||||
throw ExceptionType(stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ARC_EXCEPTIONS_HPP
|
||||
1464
flightlib/third_party/arc_utilities/include/arc_utilities/arc_helpers.hpp
vendored
Normal file
1464
flightlib/third_party/arc_utilities/include/arc_utilities/arc_helpers.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
flightlib/third_party/arc_utilities/include/arc_utilities/base64_helpers.hpp
vendored
Normal file
21
flightlib/third_party/arc_utilities/include/arc_utilities/base64_helpers.hpp
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifndef BASE64_HELPERS_HPP
|
||||
#define BASE64_HELPERS_HPP
|
||||
|
||||
namespace Base64Helpers
|
||||
{
|
||||
std::vector<uint8_t> Decode(const std::string& encoded);
|
||||
|
||||
std::string Encode(const std::vector<uint8_t>& binary);
|
||||
}
|
||||
|
||||
#endif // BASE64_HELPERS_HPP
|
||||
984
flightlib/third_party/arc_utilities/include/arc_utilities/dijkstras.hpp
vendored
Normal file
984
flightlib/third_party/arc_utilities/include/arc_utilities/dijkstras.hpp
vendored
Normal file
@@ -0,0 +1,984 @@
|
||||
#ifndef DIJKSTRAS_HPP
|
||||
#define DIJKSTRAS_HPP
|
||||
|
||||
#include <random>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <Eigen/Geometry>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/serialization.hpp>
|
||||
|
||||
namespace arc_dijkstras
|
||||
{
|
||||
class GraphEdge
|
||||
{
|
||||
protected:
|
||||
|
||||
int64_t from_index_;
|
||||
int64_t to_index_;
|
||||
double weight_;
|
||||
|
||||
public:
|
||||
|
||||
static uint64_t Serialize(const GraphEdge& edge, std::vector<uint8_t>& buffer)
|
||||
{
|
||||
return edge.SerializeSelf(buffer);
|
||||
}
|
||||
|
||||
static std::pair<GraphEdge, uint64_t> Deserialize(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
GraphEdge temp_edge;
|
||||
const uint64_t bytes_read = temp_edge.DeserializeSelf(buffer, current);
|
||||
return std::make_pair(temp_edge, bytes_read);
|
||||
}
|
||||
|
||||
GraphEdge(const int64_t from_index, const int64_t to_index, const double weight)
|
||||
: from_index_(from_index), to_index_(to_index), weight_(weight)
|
||||
{}
|
||||
|
||||
GraphEdge()
|
||||
: from_index_(-1), to_index_(-1), weight_(0.0)
|
||||
{}
|
||||
|
||||
uint64_t SerializeSelf(std::vector<uint8_t>& buffer) const
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(from_index_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(to_index_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(weight_, buffer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint64_t DeserializeSelf(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
const std::pair<int64_t, uint64_t> deserialized_from_index = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
from_index_ = deserialized_from_index.first;
|
||||
current_position += deserialized_from_index.second;
|
||||
const std::pair<int64_t, uint64_t> deserialized_to_index = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
to_index_ = deserialized_to_index.first;
|
||||
current_position += deserialized_to_index.second;
|
||||
const std::pair<double, uint64_t> deserialized_weight = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
weight_ = deserialized_weight.first;
|
||||
current_position += deserialized_weight.second;
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
bool operator==(const GraphEdge& other) const
|
||||
{
|
||||
return (from_index_ == other.GetFromIndex() && to_index_ == other.GetToIndex() && weight_ == other.GetWeight());
|
||||
}
|
||||
|
||||
std::string Print() const
|
||||
{
|
||||
return std::string("(" + std::to_string(from_index_) + "->" + std::to_string(to_index_) + ") : " + std::to_string(weight_));
|
||||
}
|
||||
|
||||
int64_t GetFromIndex() const
|
||||
{
|
||||
return from_index_;
|
||||
}
|
||||
|
||||
int64_t GetToIndex() const
|
||||
{
|
||||
return to_index_;
|
||||
}
|
||||
|
||||
double GetWeight() const
|
||||
{
|
||||
return weight_;
|
||||
}
|
||||
|
||||
void SetFromIndex(const int64_t new_from_index)
|
||||
{
|
||||
from_index_ = new_from_index;
|
||||
}
|
||||
|
||||
void SetToIndex(const int64_t new_to_index)
|
||||
{
|
||||
to_index_ = new_to_index;
|
||||
}
|
||||
|
||||
void SetWeight(const double new_weight)
|
||||
{
|
||||
weight_ = new_weight;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& stream, const GraphEdge& edge)
|
||||
{
|
||||
stream << edge.Print();
|
||||
return stream;
|
||||
}
|
||||
|
||||
template<typename NodeValueType, typename Allocator = std::allocator<NodeValueType>>
|
||||
class GraphNode
|
||||
{
|
||||
protected:
|
||||
|
||||
NodeValueType value_;
|
||||
double distance_;
|
||||
std::vector<GraphEdge> in_edges_;
|
||||
std::vector<GraphEdge> out_edges_;
|
||||
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
static uint64_t Serialize(
|
||||
const GraphNode<NodeValueType, Allocator>& node,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const NodeValueType&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
return node.SerializeSelf(buffer, value_serializer);
|
||||
}
|
||||
|
||||
static std::pair<GraphNode<NodeValueType, Allocator>, uint64_t> Deserialize(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<NodeValueType, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
GraphNode<NodeValueType, Allocator> temp_node;
|
||||
const uint64_t bytes_read = temp_node.DeserializeSelf(buffer, current, value_deserializer);
|
||||
return std::make_pair(temp_node, bytes_read);
|
||||
}
|
||||
|
||||
GraphNode(
|
||||
const NodeValueType& value,
|
||||
const double distance,
|
||||
const std::vector<GraphEdge>& new_in_edges,
|
||||
const std::vector<GraphEdge>& new_out_edges)
|
||||
: value_(value)
|
||||
, distance_(distance)
|
||||
, in_edges_(new_in_edges)
|
||||
, out_edges_(new_out_edges)
|
||||
{}
|
||||
|
||||
GraphNode(const NodeValueType& value)
|
||||
: value_(value)
|
||||
, distance_(std::numeric_limits<double>::infinity())
|
||||
{}
|
||||
|
||||
GraphNode()
|
||||
: distance_(std::numeric_limits<double>::infinity())
|
||||
{}
|
||||
|
||||
uint64_t SerializeSelf(
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const NodeValueType&, std::vector<uint8_t>&)>& value_serializer) const
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// Serialize the value
|
||||
value_serializer(value_, buffer);
|
||||
// Serialize the distance
|
||||
arc_utilities::SerializeFixedSizePOD<double>(distance_, buffer);
|
||||
// Serialize the in edges
|
||||
arc_utilities::SerializeVector<GraphEdge>(in_edges_, buffer, GraphEdge::Serialize);
|
||||
// Serialize the in edges
|
||||
arc_utilities::SerializeVector<GraphEdge>(out_edges_, buffer, GraphEdge::Serialize);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint64_t DeserializeSelf(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<NodeValueType, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
// Deserialize the value
|
||||
const std::pair<NodeValueType, uint64_t> value_deserialized = value_deserializer(buffer, current_position);
|
||||
value_ = value_deserialized.first;
|
||||
current_position += value_deserialized.second;
|
||||
// Deserialize the distace
|
||||
const std::pair<double, uint64_t> distance_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
distance_ = distance_deserialized.first;
|
||||
current_position += distance_deserialized.second;
|
||||
// Deserialize the in edges
|
||||
const std::pair<std::vector<GraphEdge>, uint64_t> in_edges_deserialized = arc_utilities::DeserializeVector<GraphEdge>(buffer, current_position, GraphEdge::Deserialize);
|
||||
in_edges_ = in_edges_deserialized.first;
|
||||
current_position += in_edges_deserialized.second;
|
||||
// Deserialize the out edges
|
||||
const std::pair<std::vector<GraphEdge>, uint64_t> out_edges_deserialized = arc_utilities::DeserializeVector<GraphEdge>(buffer, current_position, GraphEdge::Deserialize);
|
||||
out_edges_ = out_edges_deserialized.first;
|
||||
current_position += out_edges_deserialized.second;
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
std::string Print() const
|
||||
{
|
||||
std::ostringstream strm;
|
||||
strm << "Node : " << distance_ << " In Edges : ";
|
||||
if (in_edges_.size() > 0)
|
||||
{
|
||||
strm << in_edges_[0].Print();
|
||||
for (size_t idx = 1; idx < in_edges_.size(); idx++)
|
||||
{
|
||||
strm << ", " << in_edges_[idx].Print();
|
||||
}
|
||||
}
|
||||
strm << " Out Edges : ";
|
||||
if (out_edges_.size() > 0)
|
||||
{
|
||||
strm << out_edges_[0].Print();
|
||||
for (size_t idx = 1; idx < out_edges_.size(); idx++)
|
||||
{
|
||||
strm << ", " << out_edges_[idx].Print();
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
const NodeValueType& GetValueImmutable() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
NodeValueType& GetValueMutable()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
void AddInEdge(const GraphEdge& new_in_edge)
|
||||
{
|
||||
in_edges_.push_back(new_in_edge);
|
||||
}
|
||||
|
||||
void AddOutEdge(const GraphEdge& new_out_edge)
|
||||
{
|
||||
out_edges_.push_back(new_out_edge);
|
||||
}
|
||||
|
||||
void AddEdgePair(const GraphEdge& new_in_edge, const GraphEdge& new_out_edge)
|
||||
{
|
||||
AddInEdge(new_in_edge);
|
||||
AddOutEdge(new_out_edge);
|
||||
}
|
||||
|
||||
double GetDistance() const
|
||||
{
|
||||
return distance_;
|
||||
}
|
||||
|
||||
void SetDistance(const double distance)
|
||||
{
|
||||
distance_ = distance;
|
||||
}
|
||||
|
||||
const std::vector<GraphEdge>& GetInEdgesImmutable() const
|
||||
{
|
||||
return in_edges_;
|
||||
}
|
||||
|
||||
std::vector<GraphEdge>& GetInEdgesMutable()
|
||||
{
|
||||
return in_edges_;
|
||||
}
|
||||
|
||||
const std::vector<GraphEdge>& GetOutEdgesImmutable() const
|
||||
{
|
||||
return out_edges_;
|
||||
}
|
||||
|
||||
std::vector<GraphEdge>& GetOutEdgesMutable()
|
||||
{
|
||||
return out_edges_;
|
||||
}
|
||||
|
||||
void SetInEdges(const std::vector<GraphEdge>& new_in_edges)
|
||||
{
|
||||
in_edges_ = new_in_edges;
|
||||
}
|
||||
|
||||
void SetOutEdges(const std::vector<GraphEdge>& new_out_edges)
|
||||
{
|
||||
out_edges_ = new_out_edges;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename NodeValueType, typename Allocator = std::allocator<NodeValueType>>
|
||||
class Graph
|
||||
{
|
||||
protected:
|
||||
|
||||
std::vector<GraphNode<NodeValueType, Allocator>> nodes_;
|
||||
|
||||
size_t MarkConnectedComponentUndirected(
|
||||
const int64_t starting_node_idx,
|
||||
std::vector<uint32_t>& components,
|
||||
const uint32_t component_id) const
|
||||
{
|
||||
// When we push into the queue, we mark as connected, so we don't need a separate "queued" tracker to
|
||||
// avoid duplication, unlike what is used in CollisionMapGrid::MarkConnectedComponent
|
||||
std::queue<int64_t> working_queue;
|
||||
working_queue.push(starting_node_idx);
|
||||
size_t num_marked = 1;
|
||||
|
||||
while (working_queue.size() > 0)
|
||||
{
|
||||
const auto next_node_idx = working_queue.front();
|
||||
working_queue.pop();
|
||||
|
||||
const auto& out_edges = nodes_[next_node_idx].GetOutEdgesImmutable();
|
||||
for (const auto& edge : out_edges)
|
||||
{
|
||||
const auto neighbour_idx = edge.GetToIndex();
|
||||
if (components[neighbour_idx] == 0)
|
||||
{
|
||||
components[neighbour_idx] = component_id;
|
||||
++num_marked;
|
||||
working_queue.push(neighbour_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_marked;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static uint64_t Serialize(
|
||||
const Graph<NodeValueType,
|
||||
Allocator>& graph, std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const NodeValueType&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
return graph.SerializeSelf(buffer, value_serializer);
|
||||
}
|
||||
|
||||
static std::pair<Graph<NodeValueType, Allocator>, uint64_t> Deserialize(
|
||||
const std::vector<uint8_t>& buffer, const uint64_t current,
|
||||
const std::function<std::pair<NodeValueType, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
Graph<NodeValueType, Allocator> temp_graph;
|
||||
const uint64_t bytes_read = temp_graph.DeserializeSelf(buffer, current, value_deserializer);
|
||||
return std::make_pair(temp_graph, bytes_read);
|
||||
}
|
||||
|
||||
Graph(const std::vector<GraphNode<NodeValueType, Allocator>>& nodes)
|
||||
{
|
||||
if (CheckGraphLinkage(nodes))
|
||||
{
|
||||
nodes_ = nodes;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("Invalid graph linkage");
|
||||
}
|
||||
}
|
||||
|
||||
Graph(const size_t expected_size)
|
||||
{
|
||||
nodes_.reserve(expected_size);
|
||||
}
|
||||
|
||||
Graph()
|
||||
{}
|
||||
|
||||
uint64_t SerializeSelf(
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const NodeValueType&, std::vector<uint8_t>&)>& value_serializer) const
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
const auto graph_state_serializer = std::bind(GraphNode<NodeValueType, Allocator>::Serialize, std::placeholders::_1, std::placeholders::_2, value_serializer);
|
||||
arc_utilities::SerializeVector<GraphNode<NodeValueType, Allocator>>(nodes_, buffer, graph_state_serializer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint64_t DeserializeSelf(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<NodeValueType, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
const auto graph_state_deserializer = std::bind(GraphNode<NodeValueType, Allocator>::Deserialize, std::placeholders::_1, std::placeholders::_2, value_deserializer);
|
||||
const auto deserialized_nodes = arc_utilities::DeserializeVector<GraphNode<NodeValueType, Allocator>>(buffer, current, graph_state_deserializer);
|
||||
nodes_ = deserialized_nodes.first;
|
||||
return deserialized_nodes.second;
|
||||
}
|
||||
|
||||
std::string Print() const
|
||||
{
|
||||
std::ostringstream strm;
|
||||
strm << "Graph - Nodes : ";
|
||||
if (nodes_.size() > 0)
|
||||
{
|
||||
strm << nodes_[0].Print();
|
||||
for (size_t idx = 1; idx < nodes_.size(); idx++)
|
||||
{
|
||||
strm << "\n" << nodes_[idx].Print();
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
void ShrinkToFit()
|
||||
{
|
||||
nodes_.shrink_to_fit();
|
||||
}
|
||||
|
||||
bool CheckGraphLinkage() const
|
||||
{
|
||||
return CheckGraphLinkage(GetNodesImmutable());
|
||||
}
|
||||
|
||||
static bool CheckGraphLinkage(const Graph<NodeValueType, Allocator>& graph)
|
||||
{
|
||||
return CheckGraphLinkage(graph.GetNodesImmutable());
|
||||
}
|
||||
|
||||
static bool CheckGraphLinkage(const std::vector<GraphNode<NodeValueType, Allocator>>& nodes)
|
||||
{
|
||||
// Go through every node and make sure the edges are valid
|
||||
for (size_t idx = 0; idx < nodes.size(); idx++)
|
||||
{
|
||||
const GraphNode<NodeValueType, Allocator>& current_node = nodes[idx];
|
||||
// Check the in edges first
|
||||
const std::vector<GraphEdge>& in_edges = current_node.GetInEdgesImmutable();
|
||||
for (size_t in_edge_idx = 0; in_edge_idx < in_edges.size(); in_edge_idx++)
|
||||
{
|
||||
const GraphEdge& current_edge = in_edges[in_edge_idx];
|
||||
// Check from index to make sure it's in bounds
|
||||
const int64_t from_index = current_edge.GetFromIndex();
|
||||
if (from_index < 0 || from_index >= (int64_t)nodes.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check to index to make sure it matches our own index
|
||||
const int64_t to_index = current_edge.GetToIndex();
|
||||
if (to_index != (int64_t)idx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check edge validity (edges to ourself are not allowed)
|
||||
if (from_index == to_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check to make sure that the from index node is linked to us
|
||||
const GraphNode<NodeValueType, Allocator>& from_node = nodes[(size_t)from_index];
|
||||
const std::vector<GraphEdge>& from_node_out_edges = from_node.GetOutEdgesImmutable();
|
||||
bool from_node_connection_valid = false;
|
||||
// Make sure at least one out edge of the from index node corresponds to the current node
|
||||
for (size_t from_node_out_edge_idx = 0; from_node_out_edge_idx < from_node_out_edges.size(); from_node_out_edge_idx++)
|
||||
{
|
||||
const GraphEdge& current_from_node_out_edge = from_node_out_edges[from_node_out_edge_idx];
|
||||
if (current_from_node_out_edge.GetToIndex() == (int64_t)idx)
|
||||
{
|
||||
from_node_connection_valid = true;
|
||||
}
|
||||
}
|
||||
if (from_node_connection_valid == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check the out edges second
|
||||
const std::vector<GraphEdge>& out_edges = current_node.GetOutEdgesImmutable();
|
||||
for (size_t out_edge_idx = 0; out_edge_idx < out_edges.size(); out_edge_idx++)
|
||||
{
|
||||
const GraphEdge& current_edge = out_edges[out_edge_idx];
|
||||
// Check from index to make sure it matches our own index
|
||||
const int64_t from_index = current_edge.GetFromIndex();
|
||||
if (from_index != (int64_t)idx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check to index to make sure it's in bounds
|
||||
const int64_t to_index = current_edge.GetToIndex();
|
||||
if (to_index < 0 || to_index >= (int64_t)nodes.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check edge validity (edges to ourself are not allowed)
|
||||
if (from_index == to_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check to make sure that the to index node is linked to us
|
||||
const GraphNode<NodeValueType, Allocator>& to_node = nodes[(size_t)to_index];
|
||||
const std::vector<GraphEdge>& to_node_in_edges = to_node.GetInEdgesImmutable();
|
||||
bool to_node_connection_valid = false;
|
||||
// Make sure at least one in edge of the to index node corresponds to the current node
|
||||
for (size_t to_node_in_edge_idx = 0; to_node_in_edge_idx < to_node_in_edges.size(); to_node_in_edge_idx++)
|
||||
{
|
||||
const GraphEdge& current_to_node_in_edge = to_node_in_edges[to_node_in_edge_idx];
|
||||
if (current_to_node_in_edge.GetFromIndex() == (int64_t)idx)
|
||||
{
|
||||
to_node_connection_valid = true;
|
||||
}
|
||||
}
|
||||
if (to_node_connection_valid == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<GraphNode<NodeValueType, Allocator>>& GetNodesImmutable() const
|
||||
{
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
std::vector<GraphNode<NodeValueType, Allocator>>& GetNodesMutable()
|
||||
{
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
const GraphNode<NodeValueType, Allocator>& GetNodeImmutable(const int64_t index) const
|
||||
{
|
||||
assert(index >= 0);
|
||||
assert(index < (int64_t)nodes_.size());
|
||||
return nodes_[(size_t)index];
|
||||
}
|
||||
|
||||
GraphNode<NodeValueType, Allocator>& GetNodeMutable(const int64_t index)
|
||||
{
|
||||
assert(index >= 0);
|
||||
assert(index < (int64_t)nodes_.size());
|
||||
return nodes_[(size_t)index];
|
||||
}
|
||||
|
||||
int64_t AddNode(const GraphNode<NodeValueType, Allocator>& new_node)
|
||||
{
|
||||
nodes_.push_back(new_node);
|
||||
return (int64_t)(nodes_.size() - 1);
|
||||
}
|
||||
|
||||
int64_t AddNode(const NodeValueType& new_value)
|
||||
{
|
||||
nodes_.push_back(GraphNode<NodeValueType, Allocator>(new_value));
|
||||
return (int64_t)(nodes_.size() - 1);
|
||||
}
|
||||
|
||||
void AddEdgeBetweenNodes(const int64_t from_index, const int64_t to_index, const double edge_weight)
|
||||
{
|
||||
assert(from_index >= 0);
|
||||
assert(from_index < (int64_t)nodes_.size());
|
||||
assert(to_index >= 0);
|
||||
assert(to_index < (int64_t)nodes_.size());
|
||||
assert(from_index != to_index);
|
||||
const GraphEdge new_edge(from_index, to_index, edge_weight);
|
||||
GetNodeMutable(from_index).AddOutEdge(new_edge);
|
||||
GetNodeMutable(to_index).AddInEdge(new_edge);
|
||||
}
|
||||
|
||||
void AddEdgesBetweenNodes(const int64_t first_index, const int64_t second_index, const double edge_weight)
|
||||
{
|
||||
assert(first_index >= 0);
|
||||
assert(first_index < (int64_t)nodes_.size());
|
||||
assert(second_index >= 0);
|
||||
assert(second_index < (int64_t)nodes_.size());
|
||||
assert(first_index != second_index);
|
||||
const GraphEdge first_edge(first_index, second_index, edge_weight);
|
||||
GetNodeMutable(first_index).AddOutEdge(first_edge);
|
||||
GetNodeMutable(second_index).AddInEdge(first_edge);
|
||||
const GraphEdge second_edge(second_index, first_index, edge_weight);
|
||||
GetNodeMutable(second_index).AddOutEdge(second_edge);
|
||||
GetNodeMutable(first_index).AddInEdge(second_edge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GetConnectedComponentsUndirected
|
||||
* @return A vector of the component ids for each node, and the total number of components
|
||||
*/
|
||||
std::pair<std::vector<uint32_t>, uint32_t> GetConnectedComponentsUndirected() const
|
||||
{
|
||||
size_t total_num_marked = 0;
|
||||
auto connected_components = std::make_pair(std::vector<uint32_t>(nodes_.size(), 0), 0u);
|
||||
|
||||
for (size_t node_idx = 0; node_idx < nodes_.size() && total_num_marked < nodes_.size(); ++node_idx)
|
||||
{
|
||||
// If we have not yet marked this node, then mark it and anything it can reach
|
||||
if (connected_components.first[node_idx] == 0)
|
||||
{
|
||||
connected_components.second++;
|
||||
size_t num_marked = MarkConnectedComponentUndirected(node_idx, connected_components.first, connected_components.second);
|
||||
total_num_marked += num_marked;
|
||||
}
|
||||
}
|
||||
return connected_components;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename NodeValueType, typename Allocator = std::allocator<NodeValueType>>
|
||||
class SimpleDijkstrasAlgorithm
|
||||
{
|
||||
protected:
|
||||
|
||||
class CompareIndexFn
|
||||
{
|
||||
public:
|
||||
|
||||
constexpr bool operator()(const std::pair<int64_t, double>& lhs, const std::pair<int64_t, double>& rhs) const
|
||||
{
|
||||
return lhs.second > rhs.second;
|
||||
}
|
||||
};
|
||||
|
||||
SimpleDijkstrasAlgorithm() {}
|
||||
public:
|
||||
|
||||
typedef std::pair<Graph<NodeValueType, Allocator>, std::pair<std::vector<int64_t>, std::vector<double>>> DijkstrasResult;
|
||||
|
||||
static DijkstrasResult PerformDijkstrasAlgorithm(
|
||||
const Graph<NodeValueType, Allocator>& graph,
|
||||
const int64_t start_index)
|
||||
{
|
||||
if ((start_index < 0) && (start_index >= (int64_t)graph.GetNodesImmutable().size()))
|
||||
{
|
||||
throw std::invalid_argument("Start index out of range");
|
||||
}
|
||||
Graph<NodeValueType, Allocator> working_copy = graph;
|
||||
// Setup
|
||||
std::vector<int64_t> previous_index_map(working_copy.GetNodesImmutable().size(), -1);
|
||||
std::vector<double> distances(working_copy.GetNodesImmutable().size(), std::numeric_limits<double>::infinity());
|
||||
std::priority_queue<std::pair<int64_t, double>, std::vector<std::pair<int64_t, double>>, CompareIndexFn> queue;
|
||||
std::unordered_map<int64_t, uint32_t> explored(graph.GetNodesImmutable().size());
|
||||
for (size_t idx = 0; idx < working_copy.GetNodesImmutable().size(); idx++)
|
||||
{
|
||||
working_copy.GetNodeMutable((int64_t)idx).SetDistance(std::numeric_limits<double>::infinity());
|
||||
queue.push(std::make_pair((int64_t)idx, std::numeric_limits<double>::infinity()));
|
||||
}
|
||||
working_copy.GetNodeMutable(start_index).SetDistance(0.0);
|
||||
previous_index_map[(size_t)start_index] = start_index;
|
||||
distances[(size_t)start_index] = 0.0;
|
||||
queue.push(std::make_pair(start_index, 0.0));
|
||||
while (queue.size() > 0)
|
||||
{
|
||||
const std::pair<int64_t, double> top_node = queue.top();
|
||||
const int64_t& top_node_index = top_node.first;
|
||||
const double& top_node_distance = top_node.second;
|
||||
queue.pop();
|
||||
if (explored[top_node.first] > 0)
|
||||
{
|
||||
// We've already been here
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note that we've been here
|
||||
explored[top_node.first] = 1;
|
||||
// Get our neighbors
|
||||
const std::vector<GraphEdge>& neighbor_edges = working_copy.GetNodeImmutable(top_node_index).GetInEdgesImmutable();
|
||||
// Go through our neighbors
|
||||
for (size_t neighbor_idx = 0; neighbor_idx < neighbor_edges.size(); neighbor_idx++)
|
||||
{
|
||||
const int64_t neighbor_index = neighbor_edges[neighbor_idx].GetFromIndex();
|
||||
const double neighbor_edge_weight = neighbor_edges[neighbor_idx].GetWeight();
|
||||
const double new_neighbor_distance = top_node_distance + neighbor_edge_weight;
|
||||
// Check against the neighbor
|
||||
const double stored_neighbor_distance = working_copy.GetNodeImmutable(neighbor_index).GetDistance();
|
||||
if (new_neighbor_distance < stored_neighbor_distance)
|
||||
{
|
||||
// We've found a better way to get to this node
|
||||
// Check if it's already been explored
|
||||
if (explored[neighbor_index] > 0)
|
||||
{
|
||||
// If it's already been explored, we just update it in place
|
||||
working_copy.GetNodeMutable(neighbor_index).SetDistance(new_neighbor_distance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it hasn't been explored, we need to update it and add it to the queue
|
||||
working_copy.GetNodeMutable(neighbor_index).SetDistance(new_neighbor_distance);
|
||||
queue.push(std::make_pair(neighbor_index, new_neighbor_distance));
|
||||
}
|
||||
// Update that we're the best previous node
|
||||
previous_index_map[(size_t)neighbor_index] = top_node_index;
|
||||
distances[(size_t)neighbor_index] = new_neighbor_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do nothing
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_pair(working_copy, std::make_pair(previous_index_map, distances));
|
||||
}
|
||||
|
||||
// These functions have not been tested. Use with care.
|
||||
static uint64_t SerializeDijstrasResult(
|
||||
const DijkstrasResult& result,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const NodeValueType&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// Serialize the graph
|
||||
result.first.SerializeSelf(buffer, value_serializer);
|
||||
// Serialize the previous index
|
||||
const auto index_serializer = std::bind(arc_utilities::SerializeFixedSizePOD<int64_t>, std::placeholders::_1, std::placeholders::_2);
|
||||
SerializeVector(result.second.first, index_serializer);
|
||||
// Serialze the distances
|
||||
const auto distance_serializer = std::bind(arc_utilities::SerializeFixedSizePOD<double>, std::placeholders::_1, std::placeholders::_2);
|
||||
SerializeVector(result.second.second, distance_serializer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
// These functions have not been tested. Use with care.
|
||||
static std::pair<DijkstrasResult, uint64_t> DijstrasResult(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<NodeValueType, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
// Deserialize the graph itself
|
||||
std::pair<DijkstrasResult, uint64_t> deserialized;
|
||||
const auto graph_deserialized = Graph<NodeValueType, Allocator>::Deserialize(buffer, current_position, value_deserializer);
|
||||
deserialized.first.first = graph_deserialized.first;
|
||||
current_position += graph_deserialized.second;
|
||||
// Deserialize the previous index
|
||||
const auto index_deserializer = std::bind(arc_utilities::DeserializeFixedSizePOD<int64_t>, std::placeholders::_1, std::placeholders::_2);
|
||||
const auto prev_index_deserialized = arc_utilities::DeserializeVector<int64_t>(buffer, current_position, index_deserializer);
|
||||
deserialized.first.second.first = prev_index_deserialized.first;
|
||||
current_position += prev_index_deserialized.second;
|
||||
// Deserialize the distances
|
||||
const auto distance_deserializer = std::bind(arc_utilities::DeserializeFixedSizePOD<double>, std::placeholders::_1, std::placeholders::_2);
|
||||
const auto distance_deserialized = arc_utilities::DeserializeVector<double>(buffer, current_position, distance_deserializer);
|
||||
deserialized.first.second.second = distance_deserialized.first;
|
||||
current_position += distance_deserialized.second;
|
||||
// Figure out how many bytes were read
|
||||
deserialized.second = current_position - current;
|
||||
return deserialized;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename NodeValueType, typename Allocator = std::allocator<NodeValueType>>
|
||||
class SimpleGraphAstar
|
||||
{
|
||||
protected:
|
||||
|
||||
SimpleGraphAstar() {}
|
||||
|
||||
public:
|
||||
|
||||
static arc_helpers::AstarResult PerformLazyAstar(
|
||||
const Graph<NodeValueType, Allocator>& graph,
|
||||
const int64_t start_index,
|
||||
const int64_t goal_index,
|
||||
const std::function<bool(const Graph<NodeValueType, Allocator>&, const GraphEdge&)>& edge_validity_check_fn,
|
||||
const std::function<double(const Graph<NodeValueType, Allocator>&, const GraphEdge&)>& distance_fn,
|
||||
const std::function<double(const NodeValueType&, const NodeValueType&)>& heuristic_fn,
|
||||
const bool limit_pqueue_duplicates)
|
||||
{
|
||||
// Enforced sanity checks
|
||||
if ((start_index < 0) && (start_index >= (int64_t)graph.GetNodesImmutable().size()))
|
||||
{
|
||||
throw std::invalid_argument("Start index out of range");
|
||||
}
|
||||
if ((goal_index < 0) && (goal_index >= (int64_t)graph.GetNodesImmutable().size()))
|
||||
{
|
||||
throw std::invalid_argument("Goal index out of range");
|
||||
}
|
||||
if (start_index == goal_index)
|
||||
{
|
||||
throw std::invalid_argument("Start and goal indices must be different");
|
||||
}
|
||||
// Make helper function
|
||||
const auto heuristic_function = [&] (const int64_t node_index)
|
||||
{
|
||||
return heuristic_fn(graph.GetNodeImmutable(node_index).GetValueImmutable(), graph.GetNodeImmutable(goal_index).GetValueImmutable());
|
||||
};
|
||||
// Setup
|
||||
std::priority_queue<arc_helpers::AstarPQueueElement, std::vector<arc_helpers::AstarPQueueElement>, arc_helpers::CompareAstarPQueueElementFn> queue;
|
||||
// Optional map to reduce the number of duplicate items added to the pqueue
|
||||
// Key is the node index in the provided graph
|
||||
// Value is cost-to-come
|
||||
std::unordered_map<int64_t, double> queue_members_map;
|
||||
// Key is the node index in the provided graph
|
||||
// Value is a pair<backpointer, cost-to-come>
|
||||
// backpointer is the parent index in the provided graph
|
||||
std::unordered_map<int64_t, std::pair<int64_t, double>> explored;
|
||||
// Initialize
|
||||
queue.push(arc_helpers::AstarPQueueElement(start_index, -1, 0.0, heuristic_function(start_index)));
|
||||
if (limit_pqueue_duplicates)
|
||||
{
|
||||
queue_members_map[start_index] = 0.0;
|
||||
}
|
||||
// Search
|
||||
while (queue.size() > 0)
|
||||
{
|
||||
// Get the top of the priority queue
|
||||
const arc_helpers::AstarPQueueElement top_node = queue.top();
|
||||
queue.pop();
|
||||
// Remove from queue map if necessary
|
||||
if (limit_pqueue_duplicates)
|
||||
{
|
||||
queue_members_map.erase(top_node.NodeID());
|
||||
}
|
||||
// Check if the node has already been discovered
|
||||
const auto explored_itr = explored.find(top_node.NodeID());
|
||||
// We have not been here before, or it is cheaper now
|
||||
const bool in_explored = (explored_itr != explored.end());
|
||||
const bool explored_is_better = (in_explored) ? (top_node.CostToCome() >= explored_itr->second.second) : false;
|
||||
if (!explored_is_better)
|
||||
{
|
||||
// Add to the explored list
|
||||
explored[top_node.NodeID()] = std::make_pair(top_node.Backpointer(), top_node.CostToCome());
|
||||
// Check if we have reached the goal
|
||||
if (top_node.NodeID() == goal_index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Explore and add the children
|
||||
const std::vector<GraphEdge>& out_edges = graph.GetNodeImmutable(top_node.NodeID()).GetOutEdgesImmutable();
|
||||
for (size_t out_edge_idx = 0; out_edge_idx < out_edges.size(); out_edge_idx++)
|
||||
{
|
||||
// Get the next potential child node
|
||||
const GraphEdge& current_out_edge = out_edges[out_edge_idx];
|
||||
const int64_t child_node_index = current_out_edge.GetToIndex();
|
||||
// Check if the top node->child edge is valid
|
||||
if (edge_validity_check_fn(graph, current_out_edge))
|
||||
{
|
||||
// Compute the cost-to-come for the new child
|
||||
const double parent_cost_to_come = top_node.CostToCome();
|
||||
const double parent_to_child_cost = distance_fn(graph, current_out_edge);
|
||||
const double child_cost_to_come = parent_cost_to_come + parent_to_child_cost;
|
||||
// Check if the child state has already been explored
|
||||
const auto explored_itr = explored.find(child_node_index);
|
||||
// It is not in the explored list, or is there with a higher cost-to-come
|
||||
const bool in_explored = (explored_itr != explored.end());
|
||||
const bool explored_is_better = (in_explored) ? (child_cost_to_come >= explored_itr->second.second) : false;
|
||||
// Check if the child state is already in the queue
|
||||
bool queue_is_better = false;
|
||||
if (limit_pqueue_duplicates)
|
||||
{
|
||||
const auto queue_members_map_itr = queue_members_map.find(child_node_index);
|
||||
const bool in_queue = (queue_members_map_itr != queue_members_map.end());
|
||||
queue_is_better = (in_queue) ? (child_cost_to_come >= queue_members_map_itr->second) : false;
|
||||
}
|
||||
// Only add the new state if we need to
|
||||
if (!explored_is_better && !queue_is_better)
|
||||
{
|
||||
// Compute the heuristic for the child
|
||||
const double child_heuristic = heuristic_function(child_node_index);
|
||||
// Compute the child value
|
||||
const double child_value = child_cost_to_come + child_heuristic;
|
||||
queue.push(arc_helpers::AstarPQueueElement(child_node_index, top_node.NodeID(), child_cost_to_come, child_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arc_helpers::ExtractAstarResult(explored, start_index, goal_index);
|
||||
}
|
||||
|
||||
static arc_helpers::AstarResult PerformLazyAstar(
|
||||
const Graph<NodeValueType, Allocator>& graph,
|
||||
const int64_t start_index,
|
||||
const int64_t goal_index,
|
||||
const std::function<bool(const NodeValueType&, const NodeValueType&)>& edge_validity_check_fn,
|
||||
const std::function<double(const NodeValueType&, const NodeValueType&)>& distance_fn,
|
||||
const std::function<double(const NodeValueType&, const NodeValueType&)>& heuristic_fn,
|
||||
const bool limit_pqueue_duplicates)
|
||||
{
|
||||
const auto edge_validity_check_function = [&] (const Graph<NodeValueType, Allocator>& graph, const GraphEdge& edge)
|
||||
{
|
||||
return edge_validity_check_fn(graph.GetNodeImmutable(edge.GetFromIndex()).GetValueImmutable(), graph.GetNodeImmutable(edge.GetToIndex()).GetValueImmutable());
|
||||
};
|
||||
const auto distance_function = [&] (const Graph<NodeValueType, Allocator>& graph, const GraphEdge& edge)
|
||||
{
|
||||
return distance_fn(graph.GetNodeImmutable(edge.GetFromIndex()).GetValueImmutable(), graph.GetNodeImmutable(edge.GetToIndex()).GetValueImmutable());
|
||||
};
|
||||
return PerformLazyAstar(graph, start_index, goal_index, edge_validity_check_function, distance_function, heuristic_fn, limit_pqueue_duplicates);
|
||||
}
|
||||
|
||||
static arc_helpers::AstarResult PerformAstar(
|
||||
const Graph<NodeValueType, Allocator>& graph,
|
||||
const int64_t start_index,
|
||||
const int64_t goal_index,
|
||||
const std::function<double(const NodeValueType&, const NodeValueType&)>& heuristic_fn,
|
||||
const bool limit_pqueue_duplicates)
|
||||
{
|
||||
const auto edge_validity_check_function = [&] (const Graph<NodeValueType, Allocator>& graph, const GraphEdge& edge)
|
||||
{
|
||||
UNUSED(graph);
|
||||
if (edge.GetWeight() < std::numeric_limits<double>::infinity())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const auto distance_function = [&] (const Graph<NodeValueType, Allocator>& graph, const GraphEdge& edge)
|
||||
{
|
||||
UNUSED(graph);
|
||||
return edge.GetWeight();
|
||||
};
|
||||
return PerformLazyAstar(graph, start_index, goal_index, edge_validity_check_function, distance_function, heuristic_fn, limit_pqueue_duplicates);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename NodeValueType, typename Allocator = std::allocator<NodeValueType>>
|
||||
class GraphRandomWalk
|
||||
{
|
||||
protected:
|
||||
GraphRandomWalk() {}
|
||||
|
||||
public:
|
||||
|
||||
template <typename Generator>
|
||||
static std::vector<int64_t> PerformRandomWalk(
|
||||
const Graph<NodeValueType, Allocator>& graph,
|
||||
const int64_t start_index,
|
||||
const int64_t goal_index,
|
||||
Generator& generator)
|
||||
{
|
||||
std::uniform_int_distribution<int64_t> uniform_int_distribution;
|
||||
|
||||
std::vector<int64_t> path(1, start_index);
|
||||
|
||||
while (path.back() != goal_index)
|
||||
{
|
||||
// Collect data from the current node
|
||||
const int64_t curr_index = path.back();
|
||||
const auto& out_edges = graph.GetNodeImmutable(curr_index).GetOutEdgesImmutable();
|
||||
const auto num_edges = out_edges.size();
|
||||
|
||||
// Determine which node to step to next
|
||||
std::uniform_int_distribution<int64_t>::param_type params(0, (int64_t)(num_edges - 1));
|
||||
uniform_int_distribution.param(params);
|
||||
const int64_t next_step = uniform_int_distribution(generator);
|
||||
const auto next_index = out_edges.at(next_step).GetToIndex();
|
||||
|
||||
// If the next index is somewhere we've been already, then "trim" the loop off
|
||||
const auto it = std::find(path.begin(), path.end(), next_index);
|
||||
path.erase(it, path.end());
|
||||
|
||||
// (Re)add the new index to the path
|
||||
path.push_back(next_index);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DIJKSTRAS_HPP
|
||||
1012
flightlib/third_party/arc_utilities/include/arc_utilities/dynamic_spatial_hashed_voxel_grid.hpp
vendored
Normal file
1012
flightlib/third_party/arc_utilities/include/arc_utilities/dynamic_spatial_hashed_voxel_grid.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1569
flightlib/third_party/arc_utilities/include/arc_utilities/eigen_helpers.hpp
vendored
Normal file
1569
flightlib/third_party/arc_utilities/include/arc_utilities/eigen_helpers.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
285
flightlib/third_party/arc_utilities/include/arc_utilities/eigen_helpers_conversions.hpp
vendored
Normal file
285
flightlib/third_party/arc_utilities/include/arc_utilities/eigen_helpers_conversions.hpp
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Jacobi>
|
||||
#include <Eigen/SVD>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <arc_utilities/pretty_print.hpp>
|
||||
#include <functional>
|
||||
#include <ros/ros.h>
|
||||
#include <geometry_msgs/PointStamped.h>
|
||||
#include <geometry_msgs/PoseStamped.h>
|
||||
#include <geometry_msgs/Transform.h>
|
||||
#include <geometry_msgs/Wrench.h>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef EIGEN_HELPERS_CONVERSIONS_HPP
|
||||
#define EIGEN_HELPERS_CONVERSIONS_HPP
|
||||
|
||||
namespace EigenHelpersConversions
|
||||
{
|
||||
inline Eigen::Vector3d GeometryPointToEigenVector3d(const geometry_msgs::Point& point)
|
||||
{
|
||||
Eigen::Vector3d eigen_point(point.x, point.y, point.z);
|
||||
return eigen_point;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Point EigenVector3dToGeometryPoint(const Eigen::Vector3d& point)
|
||||
{
|
||||
geometry_msgs::Point geom_point;
|
||||
geom_point.x = point.x();
|
||||
geom_point.y = point.y();
|
||||
geom_point.z = point.z();
|
||||
return geom_point;
|
||||
}
|
||||
|
||||
inline Eigen::Vector4d GeometryPointToEigenVector4d(const geometry_msgs::Point& point)
|
||||
{
|
||||
Eigen::Vector4d eigen_point(point.x, point.y, point.z, 1.0);
|
||||
return eigen_point;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Point EigenVector4dToGeometryPoint(const Eigen::Vector4d& point)
|
||||
{
|
||||
geometry_msgs::Point geom_point;
|
||||
geom_point.x = point(0);
|
||||
geom_point.y = point(1);
|
||||
geom_point.z = point(2);
|
||||
return geom_point;
|
||||
}
|
||||
|
||||
inline geometry_msgs::PointStamped EigenVector3dToGeometryPointStamped(const Eigen::Vector3d& point, const std::string& frame_id)
|
||||
{
|
||||
geometry_msgs::PointStamped point_stamped;
|
||||
point_stamped.header.frame_id = frame_id;
|
||||
point_stamped.point = EigenVector3dToGeometryPoint(point);
|
||||
return point_stamped;
|
||||
}
|
||||
|
||||
inline Eigen::Vector3d GeometryVector3ToEigenVector3d(const geometry_msgs::Vector3& vector)
|
||||
{
|
||||
Eigen::Vector3d eigen_vector(vector.x, vector.y, vector.z);
|
||||
return eigen_vector;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Vector3 EigenVector3dToGeometryVector3(const Eigen::Vector3d& vector)
|
||||
{
|
||||
geometry_msgs::Vector3 geom_vector;
|
||||
geom_vector.x = vector.x();
|
||||
geom_vector.y = vector.y();
|
||||
geom_vector.z = vector.z();
|
||||
return geom_vector;
|
||||
}
|
||||
|
||||
inline Eigen::Quaterniond GeometryQuaternionToEigenQuaterniond(const geometry_msgs::Quaternion& quat)
|
||||
{
|
||||
Eigen::Quaterniond eigen_quaternion(quat.w, quat.x, quat.y, quat.z);
|
||||
return eigen_quaternion;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Quaternion EigenQuaterniondToGeometryQuaternion(const Eigen::Quaterniond& quat)
|
||||
{
|
||||
geometry_msgs::Quaternion geom_quaternion;
|
||||
geom_quaternion.w = quat.w();
|
||||
geom_quaternion.x = quat.x();
|
||||
geom_quaternion.y = quat.y();
|
||||
geom_quaternion.z = quat.z();
|
||||
return geom_quaternion;
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d GeometryPoseToEigenIsometry3d(const geometry_msgs::Pose& pose)
|
||||
{
|
||||
const Eigen::Translation3d trans(pose.position.x, pose.position.y, pose.position.z);
|
||||
const Eigen::Quaterniond quat(pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
|
||||
const Eigen::Isometry3d eigen_pose = trans * quat;
|
||||
return eigen_pose;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Pose EigenIsometry3dToGeometryPose(const Eigen::Isometry3d& transform)
|
||||
{
|
||||
const Eigen::Vector3d trans = transform.translation();
|
||||
const Eigen::Quaterniond quat(transform.rotation());
|
||||
geometry_msgs::Pose geom_pose;
|
||||
geom_pose.position.x = trans.x();
|
||||
geom_pose.position.y = trans.y();
|
||||
geom_pose.position.z = trans.z();
|
||||
geom_pose.orientation.w = quat.w();
|
||||
geom_pose.orientation.x = quat.x();
|
||||
geom_pose.orientation.y = quat.y();
|
||||
geom_pose.orientation.z = quat.z();
|
||||
return geom_pose;
|
||||
}
|
||||
|
||||
inline geometry_msgs::PoseStamped EigenIsometry3dToGeometryPoseStamped(const Eigen::Isometry3d& transform, const std::string& frame_id)
|
||||
{
|
||||
geometry_msgs::PoseStamped pose_stamped;
|
||||
pose_stamped.header.frame_id = frame_id;
|
||||
pose_stamped.pose = EigenIsometry3dToGeometryPose(transform);
|
||||
return pose_stamped;
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d GeometryTransformToEigenIsometry3d(const geometry_msgs::Transform& transform)
|
||||
{
|
||||
const Eigen::Translation3d trans(transform.translation.x, transform.translation.y, transform.translation.z);
|
||||
const Eigen::Quaterniond quat(transform.rotation.w, transform.rotation.x, transform.rotation.y, transform.rotation.z);
|
||||
const Eigen::Isometry3d eigen_transform = trans * quat;
|
||||
return eigen_transform;
|
||||
}
|
||||
|
||||
inline geometry_msgs::Transform EigenIsometry3dToGeometryTransform(const Eigen::Isometry3d& transform)
|
||||
{
|
||||
const Eigen::Vector3d trans = transform.translation();
|
||||
const Eigen::Quaterniond quat(transform.rotation());
|
||||
geometry_msgs::Transform geom_transform;
|
||||
geom_transform.translation.x = trans.x();
|
||||
geom_transform.translation.y = trans.y();
|
||||
geom_transform.translation.z = trans.z();
|
||||
geom_transform.rotation.w = quat.w();
|
||||
geom_transform.rotation.x = quat.x();
|
||||
geom_transform.rotation.y = quat.y();
|
||||
geom_transform.rotation.z = quat.z();
|
||||
return geom_transform;
|
||||
}
|
||||
|
||||
inline Eigen::Matrix3Xd VectorGeometryPointToEigenMatrix3Xd(const std::vector<geometry_msgs::Point>& vector_geom)
|
||||
{
|
||||
Eigen::Matrix3Xd eigen_matrix = Eigen::MatrixXd(3, vector_geom.size());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
eigen_matrix.block<3,1>(0, idx) = GeometryPointToEigenVector3d(vector_geom[idx]);
|
||||
}
|
||||
return eigen_matrix;
|
||||
}
|
||||
|
||||
inline std::vector<geometry_msgs::Point> EigenMatrix3XdToVectorGeometryPoint(const Eigen::Matrix3Xd& eigen_matrix)
|
||||
{
|
||||
std::vector<geometry_msgs::Point> vector_geom(eigen_matrix.cols());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
vector_geom[idx] = EigenVector3dToGeometryPoint(eigen_matrix.block<3,1>(0,idx));
|
||||
}
|
||||
return vector_geom;
|
||||
}
|
||||
|
||||
inline std::vector<geometry_msgs::Point> VectorEigenVector3dToVectorGeometryPoint(const EigenHelpers::VectorVector3d& vector_eigen)
|
||||
{
|
||||
std::vector<geometry_msgs::Point> vector_geom(vector_eigen.size());
|
||||
for (size_t idx = 0; idx < vector_eigen.size(); idx++)
|
||||
{
|
||||
vector_geom[idx] = EigenVector3dToGeometryPoint(vector_eigen[idx]);
|
||||
}
|
||||
return vector_geom;
|
||||
}
|
||||
|
||||
inline Eigen::Matrix3Xd VectorEigenVector3dToEigenMatrix3Xd(const EigenHelpers::VectorVector3d& vector_eigen)
|
||||
{
|
||||
Eigen::Matrix3Xd eigen_matrix(3, vector_eigen.size());
|
||||
for (size_t idx = 0; idx < vector_eigen.size(); idx++)
|
||||
{
|
||||
eigen_matrix.col(idx) = vector_eigen[idx];
|
||||
}
|
||||
return eigen_matrix;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorVector3d VectorGeometryPointToVectorEigenVector3d(const std::vector<geometry_msgs::Point>& vector_geom)
|
||||
{
|
||||
EigenHelpers::VectorVector3d vector_eigen(vector_geom.size());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
vector_eigen[idx] = GeometryPointToEigenVector3d(vector_geom[idx]);
|
||||
}
|
||||
return vector_eigen;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorVector3d VectorGeometryVector3ToEigenVector3d(const std::vector<geometry_msgs::Vector3>& vector_geom)
|
||||
{
|
||||
EigenHelpers::VectorVector3d vector_eigen(vector_geom.size());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
vector_eigen[idx] = GeometryVector3ToEigenVector3d(vector_geom[idx]);
|
||||
}
|
||||
return vector_eigen;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d VectorGeometryPoseToVectorIsometry3d(const std::vector<geometry_msgs::Pose>& vector_geom)
|
||||
{
|
||||
EigenHelpers::VectorIsometry3d vector_eigen(vector_geom.size());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
vector_eigen[idx] = GeometryPoseToEigenIsometry3d(vector_geom[idx]);
|
||||
}
|
||||
return vector_eigen;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d VectorGeometryPoseToVectorIsometry3d(const std::vector<geometry_msgs::Transform>& vector_geom)
|
||||
{
|
||||
EigenHelpers::VectorIsometry3d vector_eigen(vector_geom.size());
|
||||
for (size_t idx = 0; idx < vector_geom.size(); idx++)
|
||||
{
|
||||
vector_eigen[idx] = GeometryTransformToEigenIsometry3d(vector_geom[idx]);
|
||||
}
|
||||
return vector_eigen;
|
||||
}
|
||||
|
||||
inline std::vector<geometry_msgs::Pose> VectorIsometry3dToVectorGeometryPose(const EigenHelpers::VectorIsometry3d& vector_eigen)
|
||||
{
|
||||
std::vector<geometry_msgs::Pose> vector_geom(vector_eigen.size());
|
||||
for (size_t idx = 0; idx < vector_eigen.size(); idx++)
|
||||
{
|
||||
vector_geom[idx] = EigenIsometry3dToGeometryPose(vector_eigen[idx]);
|
||||
}
|
||||
return vector_geom;
|
||||
}
|
||||
|
||||
inline std::vector<geometry_msgs::Transform> VectorIsometry3dToVectorGeometryTransform(const EigenHelpers::VectorIsometry3d& vector_eigen)
|
||||
{
|
||||
std::vector<geometry_msgs::Transform> vector_geom(vector_eigen.size());
|
||||
for (size_t idx = 0; idx < vector_eigen.size(); idx++)
|
||||
{
|
||||
vector_geom[idx] = EigenIsometry3dToGeometryTransform(vector_eigen[idx]);
|
||||
}
|
||||
return vector_geom;
|
||||
}
|
||||
|
||||
// Convert wrench (force and torque) ROS message to Eigen typed data
|
||||
inline std::pair<Eigen::Vector3d, Eigen::Vector3d> GeometryWrenchToEigenPairVector(const geometry_msgs::Wrench& wrench)
|
||||
{
|
||||
const Eigen::Vector3d eigen_force(wrench.force.x, wrench.force.y, wrench.force.z);
|
||||
const Eigen::Vector3d eigen_torque(wrench.torque.x, wrench.torque.y, wrench.torque.z);
|
||||
const std::pair<Eigen::Vector3d, Eigen::Vector3d> eigen_wrench = std::make_pair(eigen_force, eigen_torque);
|
||||
return eigen_wrench;
|
||||
}
|
||||
|
||||
template<typename data_type, int LENGTH>
|
||||
inline Eigen::Matrix<data_type, Eigen::Dynamic, 1> VectorEigenVectorToEigenVectorX(const std::vector<Eigen::Matrix<data_type, LENGTH, 1>>& vector_eigen_input)
|
||||
{
|
||||
assert(vector_eigen_input.size() > 0);
|
||||
|
||||
Eigen::Matrix<data_type, Eigen::Dynamic, 1> eigen_result;
|
||||
eigen_result.resize((ssize_t)vector_eigen_input.size() * vector_eigen_input[0].rows());
|
||||
|
||||
for (size_t idx = 0; idx < vector_eigen_input.size(); idx++)
|
||||
{
|
||||
eigen_result.segment((ssize_t)idx * LENGTH, LENGTH) = vector_eigen_input[idx];
|
||||
}
|
||||
|
||||
return eigen_result;
|
||||
}
|
||||
|
||||
template<typename data_type, int LENGTH>
|
||||
inline std::vector<Eigen::Matrix<data_type, LENGTH, 1>, Eigen::aligned_allocator<Eigen::Matrix<data_type, LENGTH, 1>>> EigenVectorXToVectorEigenVector(const Eigen::Matrix<data_type, Eigen::Dynamic, 1>& eigen_input)
|
||||
{
|
||||
assert(eigen_input.rows() % LENGTH == 0);
|
||||
size_t num_vectors = eigen_input.rows() / LENGTH;
|
||||
|
||||
std::vector<Eigen::Matrix<data_type, LENGTH, 1>, Eigen::aligned_allocator<Eigen::Matrix<data_type, LENGTH, 1>>> vector_eigen_output(num_vectors);
|
||||
|
||||
for (size_t idx = 0; idx < num_vectors; idx++)
|
||||
{
|
||||
vector_eigen_output[idx] = eigen_input.segment<LENGTH>((ssize_t)idx * LENGTH);
|
||||
}
|
||||
|
||||
return vector_eigen_output;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EIGEN_HELPERS_CONVERSIONS_HPP
|
||||
35
flightlib/third_party/arc_utilities/include/arc_utilities/filesystem.hpp
vendored
Normal file
35
flightlib/third_party/arc_utilities/include/arc_utilities/filesystem.hpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef FILESYSTEM_HPP
|
||||
#define FILESYSTEM_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "arc_utilities/arc_exceptions.hpp"
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
void CreateDirectory(const boost::filesystem::path& p)
|
||||
{
|
||||
if (!boost::filesystem::is_directory(p))
|
||||
{
|
||||
std::cout << "\x1b[33;1m" << p << " does not exist! Creating ... ";
|
||||
|
||||
// NOTE: create_directories should be able to return true in this case
|
||||
// however due to a bug related to a trailing '/' this is not currently
|
||||
// the case in my version of boost
|
||||
// https://svn.boost.org/trac/boost/ticket/7258
|
||||
boost::filesystem::create_directories(p);
|
||||
if (boost::filesystem::is_directory(p))
|
||||
// if (boost::filesystem::create_directories(p))
|
||||
{
|
||||
std::cout << "Succeeded!\x1b[37m\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "\x1b[31;1mFailed!\x1b[37m\n";
|
||||
throw_arc_exception(std::runtime_error, "Unable to create directory, likely a 'trailing slash' issue");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FILESYSTEM_HPP
|
||||
21
flightlib/third_party/arc_utilities/include/arc_utilities/first_order_deformation.h
vendored
Normal file
21
flightlib/third_party/arc_utilities/include/arc_utilities/first_order_deformation.h
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef FIRST_ORDER_DEFORMATION_H
|
||||
#define FIRST_ORDER_DEFORMATION_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
namespace FirstOrderDeformation
|
||||
{
|
||||
typedef std::pair<ssize_t, ssize_t> ConfigType;
|
||||
typedef std::pair<ConfigType, double> ConfigAndDistType;
|
||||
typedef std::function<bool(const ssize_t row, const ssize_t col)> ValidityCheckFnType;
|
||||
|
||||
bool CheckFirstOrderDeformation(
|
||||
const ssize_t rows,
|
||||
const ssize_t cols,
|
||||
const ValidityCheckFnType& validity_check_fn);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FIRST_ORDER_DEFORMATION_H
|
||||
114
flightlib/third_party/arc_utilities/include/arc_utilities/get_neighbours.hpp
vendored
Normal file
114
flightlib/third_party/arc_utilities/include/arc_utilities/get_neighbours.hpp
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifndef GET_NEIGHBOURS_HPP
|
||||
#define GET_NEIGHBOURS_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
namespace GetNeighbours
|
||||
{
|
||||
template<typename ConfigType, typename StepType, typename Allocator = std::allocator<ConfigType>>
|
||||
inline std::vector<ConfigType, Allocator> TwoDimensional8Connected(
|
||||
const ConfigType& config,
|
||||
const StepType& min_x,
|
||||
const StepType& max_x,
|
||||
const StepType& min_y,
|
||||
const StepType& max_y,
|
||||
const StepType& step_size,
|
||||
const std::function<ConfigType(const ConfigType&)>& round_to_grid_fn,
|
||||
const std::function<bool(const ConfigType&)>& validity_check_fn)
|
||||
{
|
||||
std::vector<ConfigType, Allocator> neighbours;
|
||||
neighbours.reserve(8);
|
||||
|
||||
const StepType x_min = std::max(min_x, config[0] - step_size);
|
||||
const StepType x_max = std::min(max_x, config[0] + step_size);
|
||||
|
||||
const StepType y_min = std::max(min_y, config[1] - step_size);
|
||||
const StepType y_max = std::min(max_y, config[1] + step_size);
|
||||
|
||||
const ConfigType min_vector = round_to_grid_fn(ConfigType(x_min, y_min));
|
||||
const ConfigType max_vector = round_to_grid_fn(ConfigType(x_max, y_max));
|
||||
|
||||
for (int x_offset = -1; x_offset <= 1; ++x_offset)
|
||||
{
|
||||
const double x = config[0] + step_size * x_offset;
|
||||
for (int y_offset = -1; y_offset <= 1; ++y_offset)
|
||||
{
|
||||
const double y = config[1] + step_size * y_offset;
|
||||
const ConfigType neighbour = round_to_grid_fn(ConfigType(x, y));
|
||||
|
||||
if (min_vector[0] <= neighbour[0] && neighbour[0] <= max_vector[0] &&
|
||||
min_vector[1] <= neighbour[1] && neighbour[1] <= max_vector[1] &&
|
||||
(neighbour[0] != config[0] || neighbour[1] != config[1]) &&
|
||||
validity_check_fn(neighbour) == true)
|
||||
{
|
||||
neighbours.push_back(neighbour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
neighbours.shrink_to_fit();
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
template<typename ConfigType, typename StepType, typename Allocator = std::allocator<ConfigType>>
|
||||
inline std::vector<ConfigType, Allocator> ThreeDimensional8Connected(
|
||||
const ConfigType& config,
|
||||
const StepType& min_x,
|
||||
const StepType& max_x,
|
||||
const StepType& min_y,
|
||||
const StepType& max_y,
|
||||
const StepType& min_z,
|
||||
const StepType& max_z,
|
||||
const StepType& step_size,
|
||||
const std::function<ConfigType(const ConfigType&)>& round_to_grid_fn,
|
||||
const std::function<bool(const ConfigType&)>& validity_check_fn)
|
||||
{
|
||||
std::vector<ConfigType, Allocator> neighbours;
|
||||
neighbours.reserve(26);
|
||||
|
||||
const StepType x_min = std::max(min_x, config[0] - step_size);
|
||||
const StepType x_max = std::min(max_x, config[0] + step_size);
|
||||
|
||||
const StepType y_min = std::max(min_y, config[1] - step_size);
|
||||
const StepType y_max = std::min(max_y, config[1] + step_size);
|
||||
|
||||
const StepType z_min = std::max(min_z, config[2] - step_size);
|
||||
const StepType z_max = std::min(max_z, config[2] + step_size);
|
||||
|
||||
const ConfigType min_vector = round_to_grid_fn(ConfigType(x_min, y_min, z_min));
|
||||
const ConfigType max_vector = round_to_grid_fn(ConfigType(x_max, y_max, z_max));
|
||||
|
||||
for (int x_offset = -1; x_offset <= 1; ++x_offset)
|
||||
{
|
||||
const double x = config[0] + step_size * x_offset;
|
||||
for (int y_offset = -1; y_offset <= 1; ++y_offset)
|
||||
{
|
||||
const double y = config[1] + step_size * y_offset;
|
||||
for (int z_offset = -1; z_offset <= 1; ++z_offset)
|
||||
{
|
||||
const double z = config[2] + step_size * z_offset;
|
||||
const ConfigType neighbour = round_to_grid_fn(ConfigType(x, y, z));
|
||||
|
||||
if (min_vector[0] <= neighbour[0] && neighbour[0] <= max_vector[0] &&
|
||||
min_vector[1] <= neighbour[1] && neighbour[1] <= max_vector[1] &&
|
||||
min_vector[2] <= neighbour[2] && neighbour[2] <= max_vector[2] &&
|
||||
(neighbour[0] != config[0] || neighbour[1] != config[1] || neighbour[2] != config[2]) &&
|
||||
validity_check_fn(neighbour) == true)
|
||||
{
|
||||
neighbours.push_back(neighbour);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
neighbours.shrink_to_fit();
|
||||
return neighbours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GET_NEIGHBOURS_HPP
|
||||
171
flightlib/third_party/arc_utilities/include/arc_utilities/iiwa_14_fk_fast.hpp
vendored
Normal file
171
flightlib/third_party/arc_utilities/include/arc_utilities/iiwa_14_fk_fast.hpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <Eigen/Geometry>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef IIWA_14_FK_FAST_HPP
|
||||
#define IIWA_14_FK_FAST_HPP
|
||||
|
||||
namespace IIWA_14_FK_FAST
|
||||
{
|
||||
const size_t IIWA_14_NUM_ACTIVE_JOINTS = 7;
|
||||
const size_t IIWA_14_NUM_LINKS = 8;
|
||||
|
||||
const std::string IIWA_14_ACTIVE_JOINT_1_NAME = "iiwa_joint_1";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_2_NAME = "iiwa_joint_2";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_3_NAME = "iiwa_joint_3";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_4_NAME = "iiwa_joint_4";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_5_NAME = "iiwa_joint_5";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_6_NAME = "iiwa_joint_6";
|
||||
const std::string IIWA_14_ACTIVE_JOINT_7_NAME = "iiwa_joint_7";
|
||||
|
||||
const std::string IIWA_14_LINK_1_NAME = "iiwa_link_0";
|
||||
const std::string IIWA_14_LINK_2_NAME = "iiwa_link_1";
|
||||
const std::string IIWA_14_LINK_3_NAME = "iiwa_link_2";
|
||||
const std::string IIWA_14_LINK_4_NAME = "iiwa_link_3";
|
||||
const std::string IIWA_14_LINK_5_NAME = "iiwa_link_4";
|
||||
const std::string IIWA_14_LINK_6_NAME = "iiwa_link_5";
|
||||
const std::string IIWA_14_LINK_7_NAME = "iiwa_link_6";
|
||||
const std::string IIWA_14_LINK_8_NAME = "iiwa_link_7";
|
||||
|
||||
inline Eigen::Isometry3d Get_link_0_joint_1_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.1575);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(0.0, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_1_joint_2_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.2025);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, M_PI);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_2_joint_3_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.2045, 0.0);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, M_PI);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_3_joint_4_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.2155);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_4_joint_5_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.1845, 0.0);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(-M_PI_2, M_PI, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_5_joint_6_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.2155);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_6_joint_7_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.081, 0.0);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(-M_PI_2, M_PI, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d GetLinkTransforms(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
assert(configuration.size() == IIWA_14_NUM_ACTIVE_JOINTS);
|
||||
EigenHelpers::VectorIsometry3d link_transforms(IIWA_14_NUM_LINKS);
|
||||
link_transforms[0] = base_transform;
|
||||
link_transforms[1] = link_transforms[0] * Get_link_0_joint_1_LinkJointTransform(configuration[0]);
|
||||
link_transforms[2] = link_transforms[1] * Get_link_1_joint_2_LinkJointTransform(configuration[1]);
|
||||
link_transforms[3] = link_transforms[2] * Get_link_2_joint_3_LinkJointTransform(configuration[2]);
|
||||
link_transforms[4] = link_transforms[3] * Get_link_3_joint_4_LinkJointTransform(configuration[3]);
|
||||
link_transforms[5] = link_transforms[4] * Get_link_4_joint_5_LinkJointTransform(configuration[4]);
|
||||
link_transforms[6] = link_transforms[5] * Get_link_5_joint_6_LinkJointTransform(configuration[5]);
|
||||
link_transforms[7] = link_transforms[6] * Get_link_6_joint_7_LinkJointTransform(configuration[6]);
|
||||
return link_transforms;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d GetLinkTransforms(const std::map<std::string, double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
std::vector<double> configuration_vector(IIWA_14_NUM_ACTIVE_JOINTS);
|
||||
configuration_vector[0] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_1_NAME, 0.0);
|
||||
configuration_vector[1] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_2_NAME, 0.0);
|
||||
configuration_vector[2] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_3_NAME, 0.0);
|
||||
configuration_vector[3] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_4_NAME, 0.0);
|
||||
configuration_vector[4] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_5_NAME, 0.0);
|
||||
configuration_vector[5] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_6_NAME, 0.0);
|
||||
configuration_vector[6] = arc_helpers::RetrieveOrDefault(configuration, IIWA_14_ACTIVE_JOINT_7_NAME, 0.0);
|
||||
return GetLinkTransforms(configuration_vector, base_transform);
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[IIWA_14_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[IIWA_14_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[IIWA_14_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[IIWA_14_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[IIWA_14_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[IIWA_14_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[IIWA_14_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[IIWA_14_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::map<std::string, double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[IIWA_14_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[IIWA_14_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[IIWA_14_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[IIWA_14_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[IIWA_14_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[IIWA_14_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[IIWA_14_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[IIWA_14_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IIWA_14_FK_FAST_HPP
|
||||
171
flightlib/third_party/arc_utilities/include/arc_utilities/iiwa_7_fk_fast.hpp
vendored
Normal file
171
flightlib/third_party/arc_utilities/include/arc_utilities/iiwa_7_fk_fast.hpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <Eigen/Geometry>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef IIWA_7_FK_FAST_HPP
|
||||
#define IIWA_7_FK_FAST_HPP
|
||||
|
||||
namespace IIWA_7_FK_FAST
|
||||
{
|
||||
const size_t IIWA_7_NUM_ACTIVE_JOINTS = 7;
|
||||
const size_t IIWA_7_NUM_LINKS = 8;
|
||||
|
||||
const std::string IIWA_7_ACTIVE_JOINT_1_NAME = "iiwa_joint_1";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_2_NAME = "iiwa_joint_2";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_3_NAME = "iiwa_joint_3";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_4_NAME = "iiwa_joint_4";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_5_NAME = "iiwa_joint_5";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_6_NAME = "iiwa_joint_6";
|
||||
const std::string IIWA_7_ACTIVE_JOINT_7_NAME = "iiwa_joint_7";
|
||||
|
||||
const std::string IIWA_7_LINK_1_NAME = "iiwa_link_0";
|
||||
const std::string IIWA_7_LINK_2_NAME = "iiwa_link_1";
|
||||
const std::string IIWA_7_LINK_3_NAME = "iiwa_link_2";
|
||||
const std::string IIWA_7_LINK_4_NAME = "iiwa_link_3";
|
||||
const std::string IIWA_7_LINK_5_NAME = "iiwa_link_4";
|
||||
const std::string IIWA_7_LINK_6_NAME = "iiwa_link_5";
|
||||
const std::string IIWA_7_LINK_7_NAME = "iiwa_link_6";
|
||||
const std::string IIWA_7_LINK_8_NAME = "iiwa_link_7";
|
||||
|
||||
inline Eigen::Isometry3d Get_link_0_joint_1_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.15);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(0.0, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_1_joint_2_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.19);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, M_PI);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_2_joint_3_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.21, 0.0);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, M_PI);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_3_joint_4_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.0, 0.19);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_4_joint_5_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.21, 0.0);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(-M_PI_2, M_PI, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_5_joint_6_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.06070, 0.19);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(M_PI_2, 0.0, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline Eigen::Isometry3d Get_link_6_joint_7_LinkJointTransform(const double joint_val)
|
||||
{
|
||||
const Eigen::Translation3d pre_joint_translation(0.0, 0.081, 0.06070);
|
||||
const Eigen::Quaterniond pre_joint_rotation = EigenHelpers::QuaternionFromUrdfRPY(-M_PI_2, M_PI, 0.0);
|
||||
const Eigen::Isometry3d pre_joint_transform = pre_joint_translation * pre_joint_rotation;
|
||||
const Eigen::Translation3d joint_translation(0.0, 0.0, 0.0);
|
||||
const Eigen::Quaterniond joint_rotation(Eigen::AngleAxisd(joint_val, Eigen::Vector3d::UnitZ()));
|
||||
const Eigen::Isometry3d joint_transform = joint_translation * joint_rotation;
|
||||
return (pre_joint_transform * joint_transform);
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d GetLinkTransforms(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
assert(configuration.size() == IIWA_7_NUM_ACTIVE_JOINTS);
|
||||
EigenHelpers::VectorIsometry3d link_transforms(IIWA_7_NUM_LINKS);
|
||||
link_transforms[0] = base_transform;
|
||||
link_transforms[1] = link_transforms[0] * Get_link_0_joint_1_LinkJointTransform(configuration[0]);
|
||||
link_transforms[2] = link_transforms[1] * Get_link_1_joint_2_LinkJointTransform(configuration[1]);
|
||||
link_transforms[3] = link_transforms[2] * Get_link_2_joint_3_LinkJointTransform(configuration[2]);
|
||||
link_transforms[4] = link_transforms[3] * Get_link_3_joint_4_LinkJointTransform(configuration[3]);
|
||||
link_transforms[5] = link_transforms[4] * Get_link_4_joint_5_LinkJointTransform(configuration[4]);
|
||||
link_transforms[6] = link_transforms[5] * Get_link_5_joint_6_LinkJointTransform(configuration[5]);
|
||||
link_transforms[7] = link_transforms[6] * Get_link_6_joint_7_LinkJointTransform(configuration[6]);
|
||||
return link_transforms;
|
||||
}
|
||||
|
||||
inline EigenHelpers::VectorIsometry3d GetLinkTransforms(const std::map<std::string, double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
std::vector<double> configuration_vector(IIWA_7_NUM_ACTIVE_JOINTS);
|
||||
configuration_vector[0] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_1_NAME, 0.0);
|
||||
configuration_vector[1] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_2_NAME, 0.0);
|
||||
configuration_vector[2] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_3_NAME, 0.0);
|
||||
configuration_vector[3] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_4_NAME, 0.0);
|
||||
configuration_vector[4] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_5_NAME, 0.0);
|
||||
configuration_vector[5] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_6_NAME, 0.0);
|
||||
configuration_vector[6] = arc_helpers::RetrieveOrDefault(configuration, IIWA_7_ACTIVE_JOINT_7_NAME, 0.0);
|
||||
return GetLinkTransforms(configuration_vector, base_transform);
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::vector<double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[IIWA_7_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[IIWA_7_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[IIWA_7_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[IIWA_7_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[IIWA_7_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[IIWA_7_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[IIWA_7_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[IIWA_7_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
|
||||
inline EigenHelpers::MapStringIsometry3d GetLinkTransformsMap(const std::map<std::string, double>& configuration, const Eigen::Isometry3d& base_transform=Eigen::Isometry3d::Identity())
|
||||
{
|
||||
const EigenHelpers::VectorIsometry3d link_transforms = GetLinkTransforms(configuration, base_transform);
|
||||
EigenHelpers::MapStringIsometry3d link_transforms_map;
|
||||
link_transforms_map[IIWA_7_LINK_1_NAME] = link_transforms[0];
|
||||
link_transforms_map[IIWA_7_LINK_2_NAME] = link_transforms[1];
|
||||
link_transforms_map[IIWA_7_LINK_3_NAME] = link_transforms[2];
|
||||
link_transforms_map[IIWA_7_LINK_4_NAME] = link_transforms[3];
|
||||
link_transforms_map[IIWA_7_LINK_5_NAME] = link_transforms[4];
|
||||
link_transforms_map[IIWA_7_LINK_6_NAME] = link_transforms[5];
|
||||
link_transforms_map[IIWA_7_LINK_7_NAME] = link_transforms[6];
|
||||
link_transforms_map[IIWA_7_LINK_8_NAME] = link_transforms[7];
|
||||
return link_transforms_map;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IIWA_7_FK_FAST_HPP
|
||||
151
flightlib/third_party/arc_utilities/include/arc_utilities/log.hpp
vendored
Normal file
151
flightlib/third_party/arc_utilities/include/arc_utilities/log.hpp
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#ifndef LOG_HPP
|
||||
#define LOG_HPP
|
||||
|
||||
#define LOG(log, message) \
|
||||
(log).logMessage( \
|
||||
static_cast<std::ostringstream&>( \
|
||||
std::ostringstream().flush() \
|
||||
<< std::setprecision(12) \
|
||||
<< (message) \
|
||||
).str() \
|
||||
)
|
||||
|
||||
#define LOG_STREAM(log, message) \
|
||||
(log).logMessage( \
|
||||
static_cast<std::ostringstream&>( \
|
||||
std::ostringstream().flush() \
|
||||
<< std::setprecision(12) \
|
||||
<< message \
|
||||
).str() \
|
||||
)
|
||||
|
||||
#define LOG_COND(log, cond, message) \
|
||||
if ((cond)) LOG(log, message)
|
||||
|
||||
|
||||
#define LOG_COND_STREAM(log, cond, message) \
|
||||
if ((cond)) LOG_STREAM(log, message)
|
||||
|
||||
// TODO: confirm that I havn't made any mistakes in this file
|
||||
namespace Log
|
||||
{
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
Log(const std::string& filename, bool add_header = true)
|
||||
: filename_(filename)
|
||||
{
|
||||
// If it hasn't been opened, assume that it is because the
|
||||
// directory doesn't exist.
|
||||
boost::filesystem::path p(filename_);
|
||||
boost::filesystem::path dir = p.parent_path();
|
||||
if (!boost::filesystem::is_directory(dir))
|
||||
{
|
||||
std::cerr << "\x1b[33;1m" << dir << " does not exist! Creating ... ";
|
||||
|
||||
// NOTE: create_directories should be able to return true in this case
|
||||
// however due to a bug related to a trailing '/' this is not currently
|
||||
// the case in my version of boost
|
||||
// https://svn.boost.org/trac/boost/ticket/7258
|
||||
boost::filesystem::create_directories(dir);
|
||||
if (boost::filesystem::is_directory(dir))
|
||||
// if (boost::filesystem::create_directories(p))
|
||||
{
|
||||
std::cerr << "Succeeded!\x1b[37m\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\x1b[31;1mFailed!\x1b[37m\n";
|
||||
}
|
||||
}
|
||||
|
||||
out_file_.open(filename, std::ios_base::out | std::ios_base::trunc);
|
||||
// check if we've succesfully opened the file
|
||||
if (!out_file_.is_open())
|
||||
{
|
||||
std::cerr << "\x1b[31;1m Unable to create folder/file to log to: " << filename << "\x1b[37m \n";
|
||||
throw std::invalid_argument("filename must be write-openable");
|
||||
}
|
||||
|
||||
if (add_header)
|
||||
{
|
||||
time_t rawtime;
|
||||
tm * timeinfo;
|
||||
char buffer[80];
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
|
||||
|
||||
out_file_ << buffer << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy constructor */
|
||||
Log(const Log& other)
|
||||
: filename_(other.filename_)
|
||||
, out_file_(filename_, std::ios_base::out | std::ios_base::app)
|
||||
{
|
||||
}
|
||||
|
||||
/** Move constructor */
|
||||
Log(Log&& other)
|
||||
: filename_(other.filename_)
|
||||
, out_file_(filename_, std::ios_base::out | std::ios_base::app)
|
||||
{
|
||||
other.out_file_.close();
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
~Log()
|
||||
{
|
||||
if (out_file_.is_open())
|
||||
{
|
||||
out_file_.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy assignment operator */
|
||||
Log& operator= (const Log& other)
|
||||
{
|
||||
Log tmp(other); // re-use copy-constructor
|
||||
*this = std::move(tmp); // re-use move-assignment
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Move assignment operator */
|
||||
Log& operator= (Log&& other)
|
||||
{
|
||||
std::swap(filename_, other.filename_);
|
||||
other.out_file_.close();
|
||||
|
||||
if (out_file_.is_open())
|
||||
{
|
||||
out_file_.close();
|
||||
}
|
||||
|
||||
out_file_.open(filename_, std::ios_base::out | std::ios_base::app);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void logMessage(const std::string& message)
|
||||
{
|
||||
out_file_ << message << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string filename_;
|
||||
std::ofstream out_file_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LOG_HPP
|
||||
81
flightlib/third_party/arc_utilities/include/arc_utilities/maybe.hpp
vendored
Normal file
81
flightlib/third_party/arc_utilities/include/arc_utilities/maybe.hpp
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef MAYBE_HPP
|
||||
#define MAYBE_HPP
|
||||
|
||||
/* Simple implementation of a Maybe/Option type (or monad, if you're into that sort of thing).
|
||||
* Allows the safe passing of a value (or lack of a value!) without the need for null values.
|
||||
*
|
||||
* For example, Maybe<double> stores a double value OR the lack of such value.
|
||||
*
|
||||
* To use this class, create a Maybe<Type> via Maybe<Type> example_maybe(Type value)
|
||||
* To assign a new value, use example_maybe = Type value
|
||||
* To check if a Maybe contains a value, use example_maybe.Valid()
|
||||
* To get the stored value, use example_maybe.Get() or example_maybe.GetImmutable()
|
||||
* Note that both getter functions assert that a valid value is containted!
|
||||
*
|
||||
*/
|
||||
namespace Maybe
|
||||
{
|
||||
template <typename T>
|
||||
class Maybe
|
||||
{
|
||||
protected:
|
||||
|
||||
bool maybe_;
|
||||
T value_;
|
||||
|
||||
public:
|
||||
|
||||
Maybe() : maybe_(false) {}
|
||||
|
||||
Maybe(const T& value) : maybe_(true), value_(value) {}
|
||||
|
||||
Maybe(T&& value) : maybe_(true), value_(value) {}
|
||||
|
||||
bool Valid() const
|
||||
{
|
||||
return maybe_;
|
||||
}
|
||||
|
||||
T& Get()
|
||||
{
|
||||
assert(maybe_);
|
||||
return value_;
|
||||
}
|
||||
|
||||
const T& GetImmutable() const
|
||||
{
|
||||
assert(maybe_);
|
||||
return value_;
|
||||
}
|
||||
|
||||
void Set(const T& value)
|
||||
{
|
||||
maybe_ = true;
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
void Set(T&& value)
|
||||
{
|
||||
maybe_ = true;
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
Maybe& operator=(const T& value)
|
||||
{
|
||||
maybe_ = true;
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Maybe& operator=(T&& value)
|
||||
{
|
||||
maybe_ = true;
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MAYBE_HPP
|
||||
781
flightlib/third_party/arc_utilities/include/arc_utilities/pretty_print.hpp
vendored
Normal file
781
flightlib/third_party/arc_utilities/include/arc_utilities/pretty_print.hpp
vendored
Normal file
@@ -0,0 +1,781 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <Eigen/Geometry>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
|
||||
#ifndef PRETTY_PRINT_HPP
|
||||
#define PRETTY_PRINT_HPP
|
||||
|
||||
// Handy functions for printing vectors and pairs
|
||||
namespace PrettyPrint
|
||||
{
|
||||
// Base template function for printing types
|
||||
template <typename T>
|
||||
inline std::string PrettyPrint(const T& toprint, const bool add_delimiters=false, const std::string& separator=", ")
|
||||
{
|
||||
UNUSED(add_delimiters);
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << toprint;
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///// PROTOTYPES ONLY /////
|
||||
///// Specializations for specific types - if you want a specialization for a new type, add it here /////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const bool& bool_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector2d& vector_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector3d& vector_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector4d& vector_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::VectorXd& vector_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::MatrixXd& matrix_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Quaterniond& quaternion_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Isometry3d& transform_to_print, const bool add_delimiters, const std::string& separator);
|
||||
|
||||
template <typename A, typename B>
|
||||
inline std::string PrettyPrint(const std::pair<A, B>& pairtoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline std::string PrettyPrint(const std::array<T, N>& arraytoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::vector<T, Allocator>& vectoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::list<T, Allocator>& listtoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::forward_list<T, Allocator>& listtoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::deque<T, Allocator>& dequetoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename A, typename B, typename Compare=std::less<A>, typename Allocator=std::allocator<std::pair<const A, B>>>
|
||||
inline std::string PrettyPrint(const std::map<A, B, Compare, Allocator>& maptoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename A, typename B, typename Compare=std::less<A>, typename Allocator=std::allocator<std::pair<const A, B>>>
|
||||
inline std::string PrettyPrint(const std::multimap<A, B, Compare, Allocator>& maptoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Compare=std::less<T>, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::set<T, Compare, Allocator>& settoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Compare=std::less<T>, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::multiset<T, Compare, Allocator>& settoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename A, typename B, typename Hash=std::hash<A>, typename Predicate=std::equal_to<A>, typename Allocator=std::allocator<std::pair<const A, B>>>
|
||||
inline std::string PrettyPrint(const std::unordered_map<A, B, Hash, Predicate, Allocator>& maptoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename A, typename B, typename Hash=std::hash<A>, typename Predicate=std::equal_to<A>, typename Allocator=std::allocator<std::pair<const A, B>>>
|
||||
inline std::string PrettyPrint(const std::unordered_multimap<A, B, Hash, Predicate, Allocator>& maptoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Hash=std::hash<T>, typename Predicate=std::equal_to<T>, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::unordered_set<T, Hash, Predicate, Allocator>& settoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
template <typename T, typename Hash=std::hash<T>, typename Predicate=std::equal_to<T>, typename Allocator=std::allocator<T>>
|
||||
inline std::string PrettyPrint(const std::unordered_multiset<T, Hash, Predicate, Allocator>& settoprint, const bool add_delimiters=false, const std::string& separator=", ");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///// IMPLEMENTATIONS ONLY /////
|
||||
///// Specializations for specific types - if you want a specialization for a new type, add it here /////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const bool& bool_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(add_delimiters);
|
||||
UNUSED(separator);
|
||||
if (bool_to_print)
|
||||
{
|
||||
return "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector2d& vector_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "Vector2d: <x: " << vector_to_print(0) << " y: " << vector_to_print(1) << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << vector_to_print(0) << ", " << vector_to_print(1);
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector3d& vector_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "Vector3d: <x: " << vector_to_print.x() << " y: " << vector_to_print.y() << " z: " << vector_to_print.z() << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << vector_to_print.x() << ", " << vector_to_print.y() << ", " << vector_to_print.z();;
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Vector4d& vector_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "Vector4d: <x: " << vector_to_print(0) << " y: " << vector_to_print(1) << " z: " << vector_to_print(2) << " w: " << vector_to_print(3) << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << vector_to_print(0) << ", " << vector_to_print(1) << ", " << vector_to_print(2) << ", " << vector_to_print(3);
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::VectorXd& vector_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
Eigen::IOFormat io_format(Eigen::StreamPrecision, 0, ", ", ", ", "", "", "", "");
|
||||
if (add_delimiters)
|
||||
{
|
||||
io_format = Eigen::IOFormat(Eigen::StreamPrecision, 0, ", ", ", ", "", "", "VectorXd: <", ">");;
|
||||
}
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
strm << vector_to_print.format(io_format);
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::MatrixXd& matrix_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
Eigen::IOFormat io_format(Eigen::StreamPrecision, 0, ", ", "\n", "", "", "", "");
|
||||
if (add_delimiters)
|
||||
{
|
||||
io_format = Eigen::IOFormat(Eigen::StreamPrecision, 0, ", ", "\n", "", "", "MatrixXd:\n[", "]");;
|
||||
}
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
strm << matrix_to_print.format(io_format);
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Quaterniond& quaternion_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "Quaterniond <x: " << quaternion_to_print.x() << " y: " << quaternion_to_print.y() << " z: " << quaternion_to_print.z() << " w: " << quaternion_to_print.w() << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << quaternion_to_print.x() << ", " << quaternion_to_print.y() << ", " << quaternion_to_print.z() << ", " << quaternion_to_print.w();
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string PrettyPrint(const Eigen::Isometry3d& transform_to_print, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
UNUSED(separator);
|
||||
std::ostringstream strm;
|
||||
strm << std::setprecision(12);
|
||||
Eigen::Vector3d vector_to_print = transform_to_print.translation();
|
||||
Eigen::Quaterniond quaternion_to_print(transform_to_print.rotation());
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "Isometry3d <x: " << vector_to_print.x() << " y: " << vector_to_print.y() << " z: " << vector_to_print.z() << ">, <x: " << quaternion_to_print.x() << " y: " << quaternion_to_print.y() << " z: " << quaternion_to_print.z() << " w: " << quaternion_to_print.w() << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << vector_to_print.x() << ", " << vector_to_print.y() << ", " << vector_to_print.z() << " : " << quaternion_to_print.x() << ", " << quaternion_to_print.y() << ", " << quaternion_to_print.z() << ", " << quaternion_to_print.w();
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline std::string PrettyPrint(const std::pair<A, B>& pairtoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "<" << PrettyPrint(pairtoprint.first, add_delimiters, separator) << ": " << PrettyPrint(pairtoprint.second, add_delimiters, separator) << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(pairtoprint.first, add_delimiters, separator) << ": " << PrettyPrint(pairtoprint.second, add_delimiters, separator);
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline std::string PrettyPrint(const std::array<T, N>& arraytoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (arraytoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "[" << PrettyPrint(arraytoprint[0], add_delimiters, separator);
|
||||
for (size_t idx = 1; idx < arraytoprint.size(); idx++)
|
||||
{
|
||||
strm << separator << PrettyPrint(arraytoprint[idx], add_delimiters, separator);
|
||||
}
|
||||
strm << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(arraytoprint[0], add_delimiters, separator);
|
||||
for (size_t idx = 1; idx < arraytoprint.size(); idx++)
|
||||
{
|
||||
strm << separator << PrettyPrint(arraytoprint[idx], add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::vector<T, Allocator>& vectoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (vectoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "[" << PrettyPrint(vectoprint[0], add_delimiters, separator);
|
||||
for (size_t idx = 1; idx < vectoprint.size(); idx++)
|
||||
{
|
||||
strm << separator << PrettyPrint(vectoprint[idx], add_delimiters, separator);
|
||||
}
|
||||
strm << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(vectoprint[0], add_delimiters, separator);
|
||||
for (size_t idx = 1; idx < vectoprint.size(); idx++)
|
||||
{
|
||||
strm << separator << PrettyPrint(vectoprint[idx], add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::list<T, Allocator>& listtoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (listtoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "[";
|
||||
typename std::list<T, Allocator>::const_iterator itr;
|
||||
for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != listtoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::list<T, Allocator>::const_iterator itr;
|
||||
for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != listtoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::forward_list<T, Allocator>& listtoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (listtoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "[";
|
||||
typename std::forward_list<T, Allocator>::const_iterator itr;
|
||||
for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != listtoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::forward_list<T, Allocator>::const_iterator itr;
|
||||
for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != listtoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::deque<T, Allocator>& dequetoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (dequetoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "[";
|
||||
typename std::deque<T, Allocator>::const_iterator itr;
|
||||
for (itr = dequetoprint.begin(); itr != dequetoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != dequetoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::deque<T, Allocator>::const_iterator itr;
|
||||
for (itr = dequetoprint.begin(); itr != dequetoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != dequetoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename Compare, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::map<A, B, Compare, Allocator>& maptoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (maptoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "{";
|
||||
typename std::map<A, B, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::map<A, B, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename Compare, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::multimap<A, B, Compare, Allocator>& maptoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (maptoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "{";
|
||||
typename std::multimap<A, B, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::multimap<A, B, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Compare, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::set<T, Compare, Allocator>& settoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (settoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "(";
|
||||
typename std::set<T, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::set<T, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Compare, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::multiset<T, Compare, Allocator>& settoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (settoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "(";
|
||||
typename std::multiset<T, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::multiset<T, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename Hash, typename Predicate, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::unordered_map<A, B, Hash, Predicate, Allocator>& maptoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (maptoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "{";
|
||||
typename std::unordered_map<A, B, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::unordered_map<A, B, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename Hash, typename Predicate, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::unordered_multimap<A, B, Hash, Predicate, Allocator>& maptoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (maptoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "{";
|
||||
typename std::unordered_multimap<A, B, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::unordered_multimap<A, B, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
|
||||
{
|
||||
std::pair<A, B> cur_pair(itr->first, itr->second);
|
||||
if (itr != maptoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(cur_pair, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::unordered_set<T, Hash, Predicate, Allocator>& settoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (settoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "(";
|
||||
typename std::unordered_set<T, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::unordered_set<T, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
template <typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
inline std::string PrettyPrint(const std::unordered_multiset<T, Hash, Predicate, Allocator>& settoprint, const bool add_delimiters, const std::string& separator)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
if (settoprint.size() > 0)
|
||||
{
|
||||
if (add_delimiters)
|
||||
{
|
||||
strm << "(";
|
||||
typename std::unordered_multiset<T, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
strm << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
typename std::unordered_multiset<T, Hash, Predicate, Allocator>::const_iterator itr;
|
||||
for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
|
||||
{
|
||||
if (itr != settoprint.begin())
|
||||
{
|
||||
strm << separator << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
strm << PrettyPrint(*itr, add_delimiters, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PRETTY_PRINT_HPP
|
||||
120
flightlib/third_party/arc_utilities/include/arc_utilities/ros_helpers.hpp
vendored
Normal file
120
flightlib/third_party/arc_utilities/include/arc_utilities/ros_helpers.hpp
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <ros/ros.h>
|
||||
#include <ros/callback_queue.h>
|
||||
|
||||
#include "arc_utilities/maybe.hpp"
|
||||
|
||||
#ifndef ROS_HELPERS_HPP
|
||||
#define ROS_HELPERS_HPP
|
||||
|
||||
#define PARAM_NAME_WIDTH (50)
|
||||
|
||||
namespace ROSHelpers
|
||||
{
|
||||
inline void Spin(const double loop_period)
|
||||
{
|
||||
while (ros::ok())
|
||||
{
|
||||
ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(loop_period));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T GetParam(const ros::NodeHandle& nh, const std::string& param_name, const T& default_val)
|
||||
{
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_INFO_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
param_val = default_val;
|
||||
ROS_WARN_STREAM_NAMED("params", "Defaulting " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " to " << param_val);
|
||||
}
|
||||
return param_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T GetParam(const ros::NodeHandle& nh, const std::string& param_name, T&& default_val)
|
||||
{
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_INFO_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
param_val = default_val;
|
||||
ROS_WARN_STREAM_NAMED("params", "Defaulting " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " to " << param_val);
|
||||
}
|
||||
return param_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T GetParamDebugLog(const ros::NodeHandle& nh, const std::string& param_name, const T& default_val)
|
||||
{
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_DEBUG_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
param_val = default_val;
|
||||
ROS_DEBUG_STREAM_NAMED("params", "Defaulting " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " to " << param_val);
|
||||
}
|
||||
return param_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T GetParamDebugLog(const ros::NodeHandle& nh, const std::string& param_name, T&& default_val)
|
||||
{
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_DEBUG_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
param_val = default_val;
|
||||
ROS_DEBUG_STREAM_NAMED("params", "Defaulting " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " to " << param_val);
|
||||
}
|
||||
return param_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Maybe::Maybe<T> GetParamRequired(const ros::NodeHandle& nh, const std::string& param_name, const std::string& calling_fn_name)
|
||||
{
|
||||
ROS_DEBUG_STREAM_NAMED("params", "No default value for " << param_name << ": Value must be on paramter sever");
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_INFO_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
return Maybe::Maybe<T>(param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
ROS_FATAL_STREAM_NAMED("params", "Cannot find " << nh.getNamespace() << "/" << param_name << " on parameter server for " << calling_fn_name << ": Value must be on paramter sever");
|
||||
return Maybe::Maybe<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Maybe::Maybe<T> GetParamRequiredDebugLog(const ros::NodeHandle& nh, const std::string& param_name, const std::string& calling_fn_name)
|
||||
{
|
||||
ROS_DEBUG_STREAM_NAMED("params", "No default value for " << param_name << ": Value must be on paramter sever");
|
||||
T param_val;
|
||||
if (nh.getParam(param_name, param_val))
|
||||
{
|
||||
ROS_DEBUG_STREAM_NAMED("params", "Retrieving " << std::left << std::setw(PARAM_NAME_WIDTH) << param_name << " as " << param_val);
|
||||
return Maybe::Maybe<T>(param_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
ROS_FATAL_STREAM_NAMED("params", "Cannot find " << nh.getNamespace() << "/" << param_name << " on parameter server for " << calling_fn_name << ": Value must be on paramter sever");
|
||||
return Maybe::Maybe<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ROS_HELPERS_HPP
|
||||
290
flightlib/third_party/arc_utilities/include/arc_utilities/serialization.hpp
vendored
Normal file
290
flightlib/third_party/arc_utilities/include/arc_utilities/serialization.hpp
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
#ifndef SERIALIZATION_HPP
|
||||
#define SERIALIZATION_HPP
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <assert.h>
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///// PROTOTYPES ONLY /////
|
||||
///// Specializations for specific types - if you want a specialization for a new type, add it here /////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
inline uint64_t SerializeFixedSizePOD(
|
||||
const T& item_to_serialize,
|
||||
std::vector<uint8_t>& buffer);
|
||||
|
||||
template<typename T>
|
||||
inline std::pair<T, uint64_t> DeserializeFixedSizePOD(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current);
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
inline uint64_t SerializeVector(
|
||||
const std::vector<T, Allocator>& vec_to_serialize, std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& item_serializer);
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
inline std::pair<std::vector<T, Allocator>, uint64_t> DeserializeVector(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& item_deserializer);
|
||||
|
||||
template<typename Key, typename T, typename Compare = std::less<Key>, typename Allocator = std::allocator<std::pair<const Key, T>>>
|
||||
inline uint64_t SerializeMap(
|
||||
const std::map<Key, T, Compare, Allocator>& map_to_serialize,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const Key&, std::vector<uint8_t>&)>& key_serializer,
|
||||
const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer);
|
||||
|
||||
template<typename Key, typename T, typename Compare = std::less<Key>, typename Allocator = std::allocator<std::pair<const Key, T>>>
|
||||
inline std::pair<std::map<Key, T, Compare, Allocator>, uint64_t> DeserializeMap(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<Key, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& key_deserializer,
|
||||
const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer);
|
||||
|
||||
template<typename First, typename Second>
|
||||
inline uint64_t SerializePair(
|
||||
const std::pair<First, Second>& pair_to_serialize,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const First&, std::vector<uint8_t>&)>& first_serializer,
|
||||
const std::function<uint64_t(const Second&, std::vector<uint8_t>&)>& second_serializer);
|
||||
|
||||
template<typename First, typename Second>
|
||||
inline const std::pair<std::pair<First, Second>, uint64_t> DeserializePair(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<First, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& first_deserializer,
|
||||
const std::function<std::pair<Second, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& second_deserializer);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///// IMPLEMENTATIONS ONLY /////
|
||||
///// Specializations for specific types - if you want a specialization for a new type, add it here /////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
inline uint64_t SerializeFixedSizePOD(
|
||||
const T& item_to_serialize,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// Fixed-size serialization via memcpy
|
||||
std::vector<uint8_t> temp_buffer(sizeof(item_to_serialize), 0x00);
|
||||
std::memcpy(&temp_buffer[0], &item_to_serialize, sizeof(item_to_serialize));
|
||||
// Move to buffer
|
||||
buffer.insert(buffer.end(), temp_buffer.begin(), temp_buffer.end());
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::pair<T, uint64_t> DeserializeFixedSizePOD(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
T temp_item;
|
||||
assert(current <= buffer.size());
|
||||
assert((current + sizeof(temp_item)) <= buffer.size());
|
||||
std::memcpy(&temp_item, &buffer[current], sizeof(temp_item));
|
||||
return std::make_pair(temp_item, sizeof(temp_item));
|
||||
}
|
||||
|
||||
template<typename CharType>
|
||||
inline uint64_t SerializeString(
|
||||
const std::basic_string<CharType>& str_to_serialize,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// First, write a uint64_t size header
|
||||
const uint64_t size = (uint64_t)str_to_serialize.size();
|
||||
SerializeFixedSizePOD<uint64_t>(size, buffer);
|
||||
// Serialize the contained items
|
||||
for (size_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
const CharType& current = str_to_serialize[idx];
|
||||
SerializeFixedSizePOD<CharType>(current, buffer);
|
||||
}
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<typename CharType>
|
||||
inline std::pair<std::basic_string<CharType>, uint64_t> DeserializeString(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
// First, try to load the header
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
// Load the header
|
||||
const std::pair<uint64_t, uint64_t> deserialized_size = DeserializeFixedSizePOD<uint64_t>(buffer, current_position);
|
||||
const uint64_t size = deserialized_size.first;
|
||||
current_position += deserialized_size.second;
|
||||
// Deserialize the items
|
||||
std::basic_string<CharType> deserialized;
|
||||
deserialized.reserve(size);
|
||||
for (uint64_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
const std::pair<CharType, uint64_t> deserialized_char = DeserializeFixedSizePOD<CharType>(buffer, current_position);
|
||||
deserialized.push_back(deserialized_char.first);
|
||||
current_position += deserialized_char.second;
|
||||
}
|
||||
deserialized.shrink_to_fit();
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return std::make_pair(deserialized, bytes_read);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
inline uint64_t SerializeVector(
|
||||
const std::vector<T, Allocator>& vec_to_serialize,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& item_serializer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// First, write a uint64_t size header
|
||||
const uint64_t size = (uint64_t)vec_to_serialize.size();
|
||||
SerializeFixedSizePOD<uint64_t>(size, buffer);
|
||||
// Serialize the contained items
|
||||
for (size_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
const T& current = vec_to_serialize[idx];
|
||||
item_serializer(current, buffer);
|
||||
}
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
inline std::pair<std::vector<T, Allocator>, uint64_t> DeserializeVector(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& item_deserializer)
|
||||
{
|
||||
// First, try to load the header
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
// Load the header
|
||||
const std::pair<uint64_t, uint64_t> deserialized_size = DeserializeFixedSizePOD<uint64_t>(buffer, current_position);
|
||||
const uint64_t size = deserialized_size.first;
|
||||
current_position += deserialized_size.second;
|
||||
// Deserialize the items
|
||||
std::vector<T, Allocator> deserialized;
|
||||
deserialized.reserve(size);
|
||||
for (uint64_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
const std::pair<T, uint64_t> deserialized_item = item_deserializer(buffer, current_position);
|
||||
deserialized.push_back(deserialized_item.first);
|
||||
current_position += deserialized_item.second;
|
||||
}
|
||||
deserialized.shrink_to_fit();
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return std::make_pair(deserialized, bytes_read);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename Compare, typename Allocator>
|
||||
inline uint64_t SerializeMap(
|
||||
const std::map<Key, T, Compare, Allocator>& map_to_serialize,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const Key&, std::vector<uint8_t>&)>& key_serializer,
|
||||
const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// First, write a uint64_t size header
|
||||
const uint64_t size = (uint64_t)map_to_serialize.size();
|
||||
SerializeFixedSizePOD<uint64_t>(size, buffer);
|
||||
// Serialize the contained items
|
||||
typename std::map<Key, T, Compare, Allocator>::const_iterator itr;
|
||||
for (itr = map_to_serialize.begin(); itr != map_to_serialize.end(); ++itr)
|
||||
{
|
||||
SerializePair<Key, T>(*itr, buffer, key_serializer, value_serializer);
|
||||
}
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename Compare, typename Allocator>
|
||||
inline std::pair<std::map<Key, T, Compare, Allocator>, uint64_t> DeserializeMap(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<Key, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& key_deserializer,
|
||||
const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
// First, try to load the header
|
||||
assert(current < buffer.size());
|
||||
uint64_t current_position = current;
|
||||
// Load the header
|
||||
const std::pair<uint64_t, uint64_t> deserialized_size = DeserializeFixedSizePOD<uint64_t>(buffer, current_position);
|
||||
const uint64_t size = deserialized_size.first;
|
||||
current_position += deserialized_size.second;
|
||||
// Deserialize the items
|
||||
std::map<Key, T, Compare, Allocator> deserialized;
|
||||
for (uint64_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
std::pair<std::pair<Key, T>, uint64_t> deserialized_pair = DeserializePair(buffer, current_position, key_deserializer, value_deserializer);
|
||||
deserialized.insert(deserialized_pair.first);
|
||||
current_position += deserialized_pair.second;
|
||||
}
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return std::make_pair(deserialized, bytes_read);
|
||||
}
|
||||
|
||||
template<typename First, typename Second>
|
||||
inline uint64_t SerializePair(
|
||||
const std::pair<First, Second>& pair_to_serialize,
|
||||
std::vector<uint8_t>& buffer,
|
||||
const std::function<uint64_t(const First&, std::vector<uint8_t>&)>& first_serializer,
|
||||
const std::function<uint64_t(const Second&, std::vector<uint8_t>&)>& second_serializer)
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
uint64_t running_total = 0u;
|
||||
// Write each element of the pair into the buffer
|
||||
running_total += first_serializer(pair_to_serialize.first, buffer);
|
||||
running_total += second_serializer(pair_to_serialize.second, buffer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
assert(bytes_written == running_total);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<typename First, typename Second>
|
||||
inline const std::pair<std::pair<First, Second>, uint64_t> DeserializePair(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current,
|
||||
const std::function<std::pair<First, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& first_deserializer,
|
||||
const std::function<std::pair<Second, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& second_deserializer)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
// Deserialize each item in the pair individually
|
||||
uint64_t current_position = current;
|
||||
const std::pair<First, uint64_t> deserialized_first = first_deserializer(buffer, current_position);
|
||||
current_position += deserialized_first.second;
|
||||
const std::pair<Second, uint64_t> deserialized_second = second_deserializer(buffer, current_position);
|
||||
current_position += deserialized_second.second;
|
||||
// Build the resulting pair
|
||||
// TODO: Why can't I used make_pair here?
|
||||
const std::pair<First, Second> deserialized(deserialized_first.first, deserialized_second.first);
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return std::make_pair(deserialized, bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SERIALIZATION_HPP
|
||||
179
flightlib/third_party/arc_utilities/include/arc_utilities/serialization_eigen.hpp
vendored
Normal file
179
flightlib/third_party/arc_utilities/include/arc_utilities/serialization_eigen.hpp
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef SERIALIZATION_EIGEN_HPP
|
||||
#define SERIALIZATION_EIGEN_HPP
|
||||
|
||||
#include "arc_utilities/serialization.hpp"
|
||||
#include "arc_utilities/eigen_helpers.hpp"
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Serialization/Deserialization functions
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Prototypes for serialization/deserialization functions
|
||||
template<typename Container>
|
||||
inline uint64_t SerializedSizeEigenType(const Container& value);
|
||||
|
||||
// For fixed-size containers only (others have a uint64_t size header first)
|
||||
template<typename Container>
|
||||
inline uint64_t SerializedSizeEigenType(void);
|
||||
|
||||
template<typename Container>
|
||||
inline uint64_t SerializeEigenType(const Container& value, std::vector<uint8_t>& buffer);
|
||||
|
||||
template<typename Container>
|
||||
inline std::pair<Container, uint64_t> DeserializeEigenType(const std::vector<uint8_t>& buffer, const uint64_t current);
|
||||
|
||||
// Concrete implementations
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType(const Eigen::VectorXd& value)
|
||||
{
|
||||
(void)(value);
|
||||
return (uint64_t)((1 * sizeof(uint64_t)) + ((size_t)value.size() * sizeof(double))); // Space for a uint64_t size header and the data
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializeEigenType(const Eigen::VectorXd& value, std::vector<uint8_t>& buffer)
|
||||
{
|
||||
// Takes a state to serialize and a buffer to serialize into
|
||||
// Return number of bytes written to buffer
|
||||
const uint64_t serialized_size = SerializedSizeEigenType(value);
|
||||
std::vector<uint8_t> temp_buffer(serialized_size, 0x00);
|
||||
// Make the header
|
||||
const uint64_t size_header = (uint64_t)value.size();
|
||||
memcpy(&temp_buffer.front(), & size_header, sizeof(size_header));
|
||||
// Copy the data
|
||||
memcpy(&(temp_buffer[sizeof(size_header)]), value.data(), (serialized_size - sizeof(size_header)));
|
||||
buffer.insert(buffer.end(), temp_buffer.begin(), temp_buffer.end());
|
||||
return serialized_size;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::pair<Eigen::VectorXd, uint64_t> DeserializeEigenType<Eigen::VectorXd>(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
assert((current + sizeof(uint64_t)) <= buffer.size());
|
||||
// Takes a buffer to read from and the starting index in the buffer
|
||||
// Return the loaded state and how many bytes we read from the buffer
|
||||
// Load the header
|
||||
uint64_t size_header = 0u;
|
||||
memcpy(&size_header, &buffer[current], sizeof(uint64_t));
|
||||
// Check buffer size
|
||||
Eigen::VectorXd temp_value = Eigen::VectorXd::Zero((ssize_t)size_header);
|
||||
const uint64_t serialized_size = SerializedSizeEigenType(temp_value);
|
||||
assert((current + serialized_size) <= buffer.size());
|
||||
// Load from the buffer
|
||||
memcpy(temp_value.data(), &buffer[current + sizeof(size_header)], (serialized_size - sizeof(size_header)));
|
||||
return std::make_pair(temp_value, serialized_size);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType(const Eigen::Vector3d& value)
|
||||
{
|
||||
(void)(value);
|
||||
return (uint64_t)(3 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType<Eigen::Vector3d>(void)
|
||||
{
|
||||
return (uint64_t)(3 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializeEigenType(const Eigen::Vector3d& value, std::vector<uint8_t>& buffer)
|
||||
{
|
||||
// Takes a state to serialize and a buffer to serialize into
|
||||
// Return number of bytes written to buffer
|
||||
std::vector<uint8_t> temp_buffer(SerializedSizeEigenType<Eigen::Vector3d>(), 0x00);
|
||||
memcpy(&temp_buffer.front(), value.data(), SerializedSizeEigenType<Eigen::Vector3d>());
|
||||
buffer.insert(buffer.end(), temp_buffer.begin(), temp_buffer.end());
|
||||
return SerializedSizeEigenType<Eigen::Vector3d>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::pair<Eigen::Vector3d, uint64_t> DeserializeEigenType<Eigen::Vector3d>(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
assert((current + SerializedSizeEigenType<Eigen::Vector3d>()) <= buffer.size());
|
||||
// Takes a buffer to read from and the starting index in the buffer
|
||||
// Return the loaded state and how many bytes we read from the buffer
|
||||
Eigen::Vector3d temp_value;
|
||||
memcpy(temp_value.data(), &buffer[current], SerializedSizeEigenType<Eigen::Vector3d>());
|
||||
return std::make_pair(temp_value, SerializedSizeEigenType<Eigen::Vector3d>());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType(const Eigen::Matrix<double, 6, 1>& value)
|
||||
{
|
||||
(void)(value);
|
||||
return (uint64_t)(6 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>(void)
|
||||
{
|
||||
return (uint64_t)(6 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializeEigenType(const Eigen::Matrix<double, 6, 1>& value, std::vector<uint8_t>& buffer)
|
||||
{
|
||||
// Takes a state to serialize and a buffer to serialize into
|
||||
// Return number of bytes written to buffer
|
||||
std::vector<uint8_t> temp_buffer(SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>(), 0x00);
|
||||
memcpy(&temp_buffer.front(), value.data(), SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>());
|
||||
buffer.insert(buffer.end(), temp_buffer.begin(), temp_buffer.end());
|
||||
return SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::pair<Eigen::Matrix<double, 6, 1>, uint64_t> DeserializeEigenType<Eigen::Matrix<double, 6, 1>>(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
assert((current + SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>()) <= buffer.size());
|
||||
// Takes a buffer to read from and the starting index in the buffer
|
||||
// Return the loaded state and how many bytes we read from the buffer
|
||||
Eigen::Matrix<double, 6, 1> temp_value;
|
||||
memcpy(temp_value.data(), &buffer[current], SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>());
|
||||
return std::make_pair(temp_value, SerializedSizeEigenType<Eigen::Matrix<double, 6, 1>>());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType(const Eigen::Isometry3d& value)
|
||||
{
|
||||
(void)(value);
|
||||
return (uint64_t)(16 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializedSizeEigenType<Eigen::Isometry3d>(void)
|
||||
{
|
||||
return (uint64_t)(16 * sizeof(double));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64_t SerializeEigenType(const Eigen::Isometry3d& value, std::vector<uint8_t>& buffer)
|
||||
{
|
||||
// Takes a state to serialize and a buffer to serialize into
|
||||
// Return number of bytes written to buffer
|
||||
std::vector<uint8_t> temp_buffer(SerializedSizeEigenType<Eigen::Isometry3d>(), 0x00);
|
||||
memcpy(&temp_buffer.front(), value.matrix().data(), SerializedSizeEigenType<Eigen::Isometry3d>());
|
||||
buffer.insert(buffer.end(), temp_buffer.begin(), temp_buffer.end());
|
||||
return SerializedSizeEigenType<Eigen::Isometry3d>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::pair<Eigen::Isometry3d, uint64_t> DeserializeEigenType<Eigen::Isometry3d>(const std::vector<uint8_t>& buffer, const uint64_t current)
|
||||
{
|
||||
assert(current < buffer.size());
|
||||
assert((current + SerializedSizeEigenType<Eigen::Isometry3d>()) <= buffer.size());
|
||||
// Takes a buffer to read from and the starting index in the buffer
|
||||
// Return the loaded state and how many bytes we read from the buffer
|
||||
Eigen::Isometry3d temp_value;
|
||||
memcpy(temp_value.matrix().data(), &buffer[current], SerializedSizeEigenType<Eigen::Isometry3d>());
|
||||
return std::make_pair(temp_value, SerializedSizeEigenType<Eigen::Isometry3d>());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SERIALIZATION_EIGEN_HPP
|
||||
241
flightlib/third_party/arc_utilities/include/arc_utilities/serialization_ros.hpp
vendored
Normal file
241
flightlib/third_party/arc_utilities/include/arc_utilities/serialization_ros.hpp
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
#ifndef SERIALIZATION_ROS_HPP
|
||||
#define SERIALIZATION_ROS_HPP
|
||||
|
||||
#include "arc_utilities/serialization.hpp"
|
||||
#include <geometry_msgs/TransformStamped.h>
|
||||
#include <geometry_msgs/PoseStamped.h>
|
||||
#include <geometry_msgs/Point.h>
|
||||
#include <geometry_msgs/Vector3.h>
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
inline uint64_t SerializeHeader(
|
||||
const std_msgs::Header& header,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeFixedSizePOD(header.seq, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(header.stamp.sec, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(header.stamp.nsec, buffer);
|
||||
bytes_written += SerializeString(header.frame_id, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<std_msgs::Header, uint64_t> DeserializeHeader(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
std_msgs::Header header;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_seq = DeserializeFixedSizePOD<decltype(header.seq)>(buffer, current + bytes_read);
|
||||
header.seq = deserialized_seq.first;
|
||||
bytes_read += deserialized_seq.second;
|
||||
const auto deserialized_sec = DeserializeFixedSizePOD<decltype(header.stamp.sec)>(buffer, current + bytes_read);
|
||||
header.stamp.sec = deserialized_sec.first;
|
||||
bytes_read += deserialized_sec.second;
|
||||
const auto deserialized_nsec = DeserializeFixedSizePOD<decltype(header.stamp.sec)>(buffer, current + bytes_read);
|
||||
header.stamp.nsec = deserialized_nsec.first;
|
||||
bytes_read += deserialized_nsec.second;
|
||||
const auto deserialized_frame_id = DeserializeString<char>(buffer, current + bytes_read);
|
||||
header.frame_id = deserialized_frame_id.first;
|
||||
bytes_read += deserialized_frame_id.second;
|
||||
return {header, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializePoint(
|
||||
const geometry_msgs::Point& point,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeFixedSizePOD(point.x, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(point.y, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(point.z, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::Point, uint64_t> DeserializePoint(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::Point point;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_x = DeserializeFixedSizePOD<decltype(point.x)>(buffer, current + bytes_read);
|
||||
point.x = deserialized_x.first;
|
||||
bytes_read += deserialized_x.second;
|
||||
const auto deserialized_y = DeserializeFixedSizePOD<decltype(point.y)>(buffer, current + bytes_read);
|
||||
point.y = deserialized_y.first;
|
||||
bytes_read += deserialized_y.second;
|
||||
const auto deserialized_z = DeserializeFixedSizePOD<decltype(point.z)>(buffer, current + bytes_read);
|
||||
point.z = deserialized_z.first;
|
||||
bytes_read += deserialized_z.second;
|
||||
return {point, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializeVector3(
|
||||
const geometry_msgs::Vector3& vector,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeFixedSizePOD(vector.x, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(vector.y, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(vector.z, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::Vector3, uint64_t> DeserializeVector3(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::Vector3 vector;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_x = DeserializeFixedSizePOD<decltype(vector.x)>(buffer, current + bytes_read);
|
||||
vector.x = deserialized_x.first;
|
||||
bytes_read += deserialized_x.second;
|
||||
const auto deserialized_y = DeserializeFixedSizePOD<decltype(vector.y)>(buffer, current + bytes_read);
|
||||
vector.y = deserialized_y.first;
|
||||
bytes_read += deserialized_y.second;
|
||||
const auto deserialized_z = DeserializeFixedSizePOD<decltype(vector.z)>(buffer, current + bytes_read);
|
||||
vector.z = deserialized_z.first;
|
||||
bytes_read += deserialized_z.second;
|
||||
return {vector, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializeQuaternion(
|
||||
const geometry_msgs::Quaternion& quat,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeFixedSizePOD(quat.x, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(quat.y, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(quat.z, buffer);
|
||||
bytes_written += SerializeFixedSizePOD(quat.w, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::Quaternion, uint64_t> DeserializeQuaternion(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::Quaternion quat;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_x = DeserializeFixedSizePOD<decltype(quat.x)>(buffer, current + bytes_read);
|
||||
quat.x = deserialized_x.first;
|
||||
bytes_read += deserialized_x.second;
|
||||
const auto deserialized_y = DeserializeFixedSizePOD<decltype(quat.y)>(buffer, current + bytes_read);
|
||||
quat.y = deserialized_y.first;
|
||||
bytes_read += deserialized_y.second;
|
||||
const auto deserialized_z = DeserializeFixedSizePOD<decltype(quat.z)>(buffer, current + bytes_read);
|
||||
quat.z = deserialized_z.first;
|
||||
bytes_read += deserialized_z.second;
|
||||
const auto deserialized_w = DeserializeFixedSizePOD<decltype(quat.z)>(buffer, current + bytes_read);
|
||||
quat.w = deserialized_w.first;
|
||||
bytes_read += deserialized_w.second;
|
||||
return {quat, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializePose(
|
||||
const geometry_msgs::Pose& pose,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializePoint(pose.position, buffer);
|
||||
bytes_written += SerializeQuaternion(pose.orientation, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::Pose, uint64_t> DeserializePose(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::Pose pose;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_position = DeserializePoint(buffer, current + bytes_read);
|
||||
pose.position = deserialized_position.first;
|
||||
bytes_read += deserialized_position.second;
|
||||
const auto deserialized_quat = DeserializeQuaternion(buffer, current + bytes_read);
|
||||
pose.orientation = deserialized_quat.first;
|
||||
bytes_read += deserialized_quat.second;
|
||||
return {pose, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializePoseStamped(
|
||||
const geometry_msgs::PoseStamped& pose,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeHeader(pose.header, buffer);
|
||||
bytes_written += SerializePose(pose.pose, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::PoseStamped, uint64_t> DeserializePoseStamped(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::PoseStamped pose;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_header = DeserializeHeader(buffer, current + bytes_read);
|
||||
pose.header = deserialized_header.first;
|
||||
bytes_read += deserialized_header.second;
|
||||
const auto deserialized_pose = DeserializePose(buffer, current + bytes_read);
|
||||
pose.pose = deserialized_pose.first;
|
||||
bytes_read += deserialized_pose.second;
|
||||
return {pose, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializeTransform(
|
||||
const geometry_msgs::Transform& transform,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeVector3(transform.translation, buffer);
|
||||
bytes_written += SerializeQuaternion(transform.rotation, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::Transform, uint64_t> DeserializeTransform(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::Transform transform;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_translation = DeserializeVector3(buffer, current + bytes_read);
|
||||
transform.translation = deserialized_translation.first;
|
||||
bytes_read += deserialized_translation.second;
|
||||
const auto deserialized_quat = DeserializeQuaternion(buffer, current + bytes_read);
|
||||
transform.rotation = deserialized_quat.first;
|
||||
bytes_read += deserialized_quat.second;
|
||||
return {transform, bytes_read};
|
||||
}
|
||||
|
||||
inline uint64_t SerializeTransformStamped(
|
||||
const geometry_msgs::TransformStamped& transform,
|
||||
std::vector<uint8_t>& buffer)
|
||||
{
|
||||
uint64_t bytes_written = 0;
|
||||
bytes_written += SerializeHeader(transform.header, buffer);
|
||||
bytes_written += SerializeTransform(transform.transform, buffer);
|
||||
bytes_written += SerializeString<char>(transform.child_frame_id, buffer);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline std::pair<geometry_msgs::TransformStamped, uint64_t> DeserializeTransformStamped(
|
||||
const std::vector<uint8_t>& buffer,
|
||||
const uint64_t current)
|
||||
{
|
||||
geometry_msgs::TransformStamped transform;
|
||||
uint64_t bytes_read = 0;
|
||||
const auto deserialized_header = DeserializeHeader(buffer, current + bytes_read);
|
||||
transform.header = deserialized_header.first;
|
||||
bytes_read += deserialized_header.second;
|
||||
const auto deserialized_transform = DeserializeTransform(buffer, current + bytes_read);
|
||||
transform.transform = deserialized_transform.first;
|
||||
bytes_read += deserialized_transform.second;
|
||||
const auto deserialized_child_frame_id = DeserializeString<char>(buffer, current + bytes_read);
|
||||
transform.child_frame_id = deserialized_child_frame_id.first;
|
||||
bytes_read += deserialized_child_frame_id.second;
|
||||
return {transform, bytes_read};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SERIALIZATION_ROS_HPP
|
||||
210
flightlib/third_party/arc_utilities/include/arc_utilities/shortcut_smoothing.hpp
vendored
Normal file
210
flightlib/third_party/arc_utilities/include/arc_utilities/shortcut_smoothing.hpp
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
#include <functional>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef SHORTCUT_SMOOTHING_HPP
|
||||
#define SHORTCUT_SMOOTHING_HPP
|
||||
|
||||
namespace shortcut_smoothing
|
||||
{
|
||||
inline EigenHelpers::VectorVector3d InterpolateWithCollisionCheck(
|
||||
const EigenHelpers::VectorVector3d& input_vector,
|
||||
const size_t first_ind,
|
||||
const size_t second_ind,
|
||||
const double step_size,
|
||||
const std::function<bool(const Eigen::Vector3d&)>& collision_fn)
|
||||
{
|
||||
const size_t starting_ind = std::min(first_ind, second_ind);
|
||||
const size_t ending_ind = std::max(first_ind, second_ind);
|
||||
|
||||
const Eigen::Vector3d& starting_point = input_vector[starting_ind];
|
||||
const Eigen::Vector3d& ending_point = input_vector[ending_ind];
|
||||
const Eigen::Vector3d delta = ending_point - starting_point;
|
||||
const Eigen::Vector3d delta_unit_vec = delta.normalized();
|
||||
|
||||
const double total_dist = delta.norm();
|
||||
|
||||
if (total_dist <= step_size)
|
||||
{
|
||||
return input_vector;
|
||||
}
|
||||
|
||||
// Collision check the path between the first and second index
|
||||
// We assume that the endpoints are not in collision, so we don't check dist == 0 or dist == total_dist
|
||||
bool collision = false;
|
||||
for (double dist = step_size; !collision && dist < total_dist; dist += step_size)
|
||||
{
|
||||
const Eigen::Vector3d point_to_check = starting_point + dist * delta_unit_vec;
|
||||
collision = collision_fn(point_to_check);
|
||||
}
|
||||
|
||||
|
||||
if (!collision)
|
||||
{
|
||||
const size_t num_original_elements = ending_ind - starting_ind - 1;
|
||||
const size_t num_new_elements = (size_t)std::ceil(total_dist / step_size);
|
||||
|
||||
EigenHelpers::VectorVector3d output_vector(input_vector.size() - num_original_elements + num_new_elements - 1);
|
||||
|
||||
// Copy in the first unchanged elements of the vector
|
||||
std::copy(input_vector.begin(), input_vector.begin() + starting_ind + 1, output_vector.begin());
|
||||
|
||||
// Assign the replaced elements
|
||||
for (size_t new_element_ind = 1; new_element_ind < num_new_elements; ++new_element_ind)
|
||||
{
|
||||
const double dist = (double)new_element_ind * step_size;
|
||||
output_vector[starting_ind + new_element_ind] = starting_point + dist * delta_unit_vec;
|
||||
}
|
||||
|
||||
// Copy in the last unchanged elements of the vector
|
||||
std::copy(input_vector.begin() + ending_ind, input_vector.end(), output_vector.begin() + starting_ind + num_new_elements);
|
||||
|
||||
return output_vector;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return input_vector;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief ShortcutSmoothPath
|
||||
* @param path
|
||||
* @param max_iterations
|
||||
* @param max_failed_iterations
|
||||
* @param max_shortcut_fraction
|
||||
* @param edge_validity_check_fn - Must match the following prototype: std::function<bool(const Configuration&, const Configuration&)>&>
|
||||
* @param prng
|
||||
* @return
|
||||
*/
|
||||
template<typename PRNG, typename Configuration, typename ConfigAlloc = std::allocator<Configuration>, class EdgeValidityCheckFn>
|
||||
inline std::vector<Configuration, ConfigAlloc> ShortcutSmoothPath(
|
||||
const std::vector<Configuration, ConfigAlloc>& path,
|
||||
const uint32_t max_iterations, const uint32_t max_failed_iterations,
|
||||
const double max_shortcut_fraction,
|
||||
const EdgeValidityCheckFn& edge_validity_check_fn,
|
||||
PRNG& prng)
|
||||
{
|
||||
std::vector<Configuration, ConfigAlloc> current_path = path;
|
||||
uint32_t num_iterations = 0;
|
||||
uint32_t failed_iterations = 0;
|
||||
while (num_iterations < max_iterations && failed_iterations < max_failed_iterations && current_path.size() > 2)
|
||||
{
|
||||
// Attempt a shortcut
|
||||
const int64_t base_index = std::uniform_int_distribution<size_t>(0, current_path.size() - 1)(prng);
|
||||
// Pick an offset fraction
|
||||
const double offset_fraction = std::uniform_real_distribution<double>(-max_shortcut_fraction, max_shortcut_fraction)(prng);
|
||||
// Compute the offset index
|
||||
const int64_t offset_index = base_index + (int64_t)((double)current_path.size() * offset_fraction); // Could be out of bounds
|
||||
const int64_t safe_offset_index = arc_helpers::ClampValue(offset_index, (int64_t)0, (int64_t)(current_path.size() - 1));
|
||||
// Get start & end indices
|
||||
const size_t start_index = (size_t)std::min(base_index, safe_offset_index);
|
||||
const size_t end_index = (size_t)std::max(base_index, safe_offset_index);
|
||||
if (end_index <= start_index + 1)
|
||||
{
|
||||
num_iterations++;
|
||||
continue;
|
||||
}
|
||||
// Check if the edge is valid
|
||||
const Configuration& start_config = current_path[start_index];
|
||||
const Configuration& end_config = current_path[end_index];
|
||||
const bool edge_valid = edge_validity_check_fn(start_config, end_config);
|
||||
if (edge_valid)
|
||||
{
|
||||
// Make the shortened path
|
||||
std::vector<Configuration, ConfigAlloc> shortened_path;
|
||||
shortened_path.insert(shortened_path.end(), current_path.begin(), current_path.begin() + start_index + 1);
|
||||
shortened_path.insert(shortened_path.end(), current_path.begin() + end_index, current_path.end());
|
||||
current_path = shortened_path;
|
||||
num_iterations++;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_iterations++;
|
||||
failed_iterations++;
|
||||
}
|
||||
}
|
||||
return current_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ResamplePathPartial Returns the resampled portion of the path between [start_ind, end_ind); *not* the whole path
|
||||
* @param path
|
||||
* @param start_ind
|
||||
* @param end_ind
|
||||
* @param resampled_state_distance
|
||||
* @param state_distance_fn - must match the following prototype: std::function<double(const Configuration&, const Configuration&, const)>
|
||||
* @param state_interpolation_fn - must match the following prototype: std::function<Configuration(const Configuration&, const Configuration&, const double)>
|
||||
* @return
|
||||
*/
|
||||
template<typename Configuration, typename ConfigAlloc = std::allocator<Configuration>, class DistanceFn, class InterpolationFn>
|
||||
inline std::vector<Configuration, ConfigAlloc> ResamplePathPartial(
|
||||
const std::vector<Configuration, ConfigAlloc>& path,
|
||||
const size_t start_ind,
|
||||
const size_t end_ind,
|
||||
const double resampled_state_distance,
|
||||
const DistanceFn& state_distance_fn,
|
||||
const InterpolationFn& state_interpolation_fn)
|
||||
{
|
||||
assert(end_ind > start_ind);
|
||||
assert(end_ind <= path.size());
|
||||
|
||||
// If we only have one element, to resample between, return it
|
||||
if (end_ind - start_ind == 1)
|
||||
{
|
||||
return std::vector<Configuration, ConfigAlloc>(1, path[start_ind]);
|
||||
}
|
||||
|
||||
// Add the first state
|
||||
std::vector<Configuration, ConfigAlloc> resampled_path;
|
||||
resampled_path.push_back(path[start_ind]);
|
||||
|
||||
// Loop through the path, adding interpolated states as needed
|
||||
for (size_t idx = start_ind; idx < end_ind - 1; idx++)
|
||||
{
|
||||
// Get the states from the original path
|
||||
const Configuration& current_state = path[idx];
|
||||
const Configuration& next_state = path[idx + 1];
|
||||
|
||||
// We want to add all the intermediate states to our returned path
|
||||
const double distance = state_distance_fn(current_state, next_state);
|
||||
const double raw_num_intervals = distance / resampled_state_distance;
|
||||
const uint32_t num_segments = (uint32_t)std::ceil(raw_num_intervals);
|
||||
|
||||
if (num_segments == 0u)
|
||||
{
|
||||
// Do nothing because this means distance was exactly 0, so we are going to discard the extra point
|
||||
}
|
||||
// If there's only one segment, we just add the end state of the window
|
||||
else if (num_segments == 1u)
|
||||
{
|
||||
resampled_path.push_back(next_state);
|
||||
}
|
||||
// If there is more than one segment, interpolate between previous_state and current_state (including the next_state)
|
||||
else
|
||||
{
|
||||
for (uint32_t segment = 1u; segment <= num_segments; segment++)
|
||||
{
|
||||
const double interpolation_ratio = (double)segment / (double)num_segments;
|
||||
const Configuration interpolated_state = state_interpolation_fn(current_state, next_state, interpolation_ratio);
|
||||
resampled_path.push_back(interpolated_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resampled_path;
|
||||
}
|
||||
|
||||
template<typename Configuration, typename ConfigAlloc = std::allocator<Configuration>, class DistanceFn, class InterpolationFn>
|
||||
inline std::vector<Configuration, ConfigAlloc> ResamplePath(
|
||||
const std::vector<Configuration, ConfigAlloc>& path,
|
||||
const double resampled_state_distance,
|
||||
const DistanceFn& state_distance_fn,
|
||||
const InterpolationFn& state_interpolation_fn)
|
||||
{
|
||||
return ResamplePathPartial(path, 0, path.size(), resampled_state_distance, state_distance_fn, state_interpolation_fn);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SHORTCUT_SMOOTHING_HPP
|
||||
205
flightlib/third_party/arc_utilities/include/arc_utilities/simple_astar_planner.hpp
vendored
Normal file
205
flightlib/third_party/arc_utilities/include/arc_utilities/simple_astar_planner.hpp
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
#ifndef SIMPLE_ASTAR_PLANNER_HPP
|
||||
#define SIMPLE_ASTAR_PLANNER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
//#include <ros/ros.h>
|
||||
//#include <visualization_msgs/Marker.h>
|
||||
//#include <arc_utilities/arc_helpers.hpp>
|
||||
//#include <arc_utilities/ros_helpers.hpp>
|
||||
//#include <arc_utilities/eigen_helpers_conversions.hpp>
|
||||
|
||||
namespace simple_astar_planner
|
||||
{
|
||||
template<typename ConfigType, typename Allocator = std::allocator<ConfigType>>
|
||||
class SimpleAStarPlanner
|
||||
{
|
||||
protected:
|
||||
SimpleAStarPlanner() {}
|
||||
|
||||
typedef std::pair<ConfigType, double> ConfigAndDistType;
|
||||
struct AStarComparator
|
||||
{
|
||||
public:
|
||||
AStarComparator(const std::function<double(const ConfigType&)>& heuristic_fn)
|
||||
: heuristic_fn_(heuristic_fn)
|
||||
{}
|
||||
|
||||
// Defines a "less" operation"; by using "greater" then the smallest element will appear at the top of the priority queue
|
||||
bool operator()(const ConfigAndDistType& c1, const ConfigAndDistType& c2) const
|
||||
{
|
||||
// If both expected distances are the same, then we want to explore the one that has the smaller heuristic distance
|
||||
if (EigenHelpers::IsApprox(c1.second, c2.second, 1e-10))
|
||||
{
|
||||
const double hdist_c1 = heuristic_fn_(c1.first);
|
||||
const double hdist_c2 = heuristic_fn_(c2.first);
|
||||
return (hdist_c1 > hdist_c2);
|
||||
}
|
||||
// If expected distances are different, we want to explore the one with the smaller expected distance
|
||||
else
|
||||
{
|
||||
return (c1.second > c2.second);
|
||||
}
|
||||
}
|
||||
|
||||
const std::function<double(const ConfigType&)>& heuristic_fn_;
|
||||
};
|
||||
|
||||
template<typename ConfigHasher = std::hash<ConfigType>>
|
||||
static std::vector<ConfigType, Allocator> ExtractPathBasic(const std::unordered_map<ConfigType, ConfigType, ConfigHasher>& backpointers, ConfigType last_state)
|
||||
{
|
||||
std::vector<ConfigType, Allocator> path;
|
||||
for (auto backpointer_ittr = backpointers.find(last_state); backpointer_ittr != backpointers.end(); backpointer_ittr = backpointers.find(last_state))
|
||||
{
|
||||
path.push_back(last_state);
|
||||
last_state = backpointer_ittr->second;
|
||||
}
|
||||
path.push_back(last_state);
|
||||
std::reverse(path.begin(), path.end());
|
||||
return path;
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename ConfigHasher = std::hash<ConfigType>>
|
||||
static std::pair<std::vector<ConfigType, Allocator>, std::map<std::string, double>> Plan(
|
||||
const ConfigType& start,
|
||||
const std::function<std::vector<ConfigType, Allocator>(const ConfigType&)>& neighbour_fn,
|
||||
const std::function<double(const ConfigType&, const ConfigType&)>& distance_fn,
|
||||
const std::function<double(const ConfigType&)>& heuristic_fn,
|
||||
const std::function<bool(const ConfigType&)>& goal_reached_fn)
|
||||
{
|
||||
const auto start_time = std::chrono::steady_clock::now();
|
||||
|
||||
// ros::NodeHandle nh;
|
||||
// visualization_msgs::Marker marker;
|
||||
// marker.header.frame_id = "mocap_world";
|
||||
// marker.type = visualization_msgs::Marker::CUBE_LIST;
|
||||
// marker.action = visualization_msgs::Marker::ADD;
|
||||
// marker.ns = "explored_states";
|
||||
// marker.id = 1;
|
||||
// marker.scale.x = ROSHelpers::GetParam(nh, "world_x_step", 1.0);
|
||||
// marker.scale.y = ROSHelpers::GetParam(nh, "world_y_step", 1.0);
|
||||
// marker.scale.z = ROSHelpers::GetParam(nh, "world_z_step", 1.0);
|
||||
// marker.points.reserve(4096);
|
||||
// marker.color = arc_helpers::RGBAColorBuilder<std_msgs::ColorRGBA>::MakeFromFloatColors(1.0, 1.0, 0.0, 1.0);
|
||||
|
||||
// visualization_msgs::Marker neighbours_marker;
|
||||
// neighbours_marker.header.frame_id = "mocap_world";
|
||||
// neighbours_marker.type = visualization_msgs::Marker::CUBE_LIST;
|
||||
// neighbours_marker.action = visualization_msgs::Marker::ADD;
|
||||
// neighbours_marker.ns = "neighbours";
|
||||
// neighbours_marker.id = 1;
|
||||
// neighbours_marker.scale.x = ROSHelpers::GetParam(nh, "world_x_step", 1.0);
|
||||
// neighbours_marker.scale.y = ROSHelpers::GetParam(nh, "world_y_step", 1.0);
|
||||
// neighbours_marker.scale.z = ROSHelpers::GetParam(nh, "world_z_step", 1.0);
|
||||
// neighbours_marker.points.reserve(26);
|
||||
// neighbours_marker.color = arc_helpers::RGBAColorBuilder<std_msgs::ColorRGBA>::MakeFromFloatColors(0.0, 0.0, 1.0, 0.3);
|
||||
|
||||
// ros::Publisher marker_pub = nh.advertise<visualization_msgs::Marker>("visualization_marker", 100, false);
|
||||
|
||||
|
||||
|
||||
std::pair<std::vector<ConfigType, Allocator>, std::map<std::string, double>> results;
|
||||
|
||||
const AStarComparator astar_compare(heuristic_fn);
|
||||
std::priority_queue<ConfigAndDistType, std::vector<ConfigAndDistType>, AStarComparator> frontier(astar_compare);
|
||||
std::unordered_set<ConfigType, ConfigHasher> explored;
|
||||
std::unordered_map<ConfigType, double, ConfigHasher> cost_to_come;
|
||||
std::unordered_map<ConfigType, ConfigType, ConfigHasher> backpointers;
|
||||
|
||||
frontier.push(ConfigAndDistType(start, heuristic_fn(start)));
|
||||
cost_to_come[start] = 0.0;
|
||||
|
||||
bool goal_reached = false;
|
||||
while (!goal_reached && frontier.size() > 0)
|
||||
{
|
||||
const ConfigAndDistType current = frontier.top();
|
||||
frontier.pop();
|
||||
const ConfigType& current_node = current.first;
|
||||
|
||||
if (goal_reached_fn(current_node) == true)
|
||||
{
|
||||
results.first = ExtractPathBasic(backpointers, current_node);
|
||||
goal_reached = true;
|
||||
}
|
||||
// Double check if we've already explored this node:
|
||||
// a single node can be inserted into the frontier multiple times at the same or different priorities
|
||||
// so we want to avoid the expense of re-exploring it, and just discard this one once we pop it
|
||||
else if (explored.find(current_node) == explored.end())
|
||||
{
|
||||
// geometry_msgs::Point p;
|
||||
// p.x = current_node[0];
|
||||
// p.y = current_node[1];
|
||||
// p.z = current_node[2];
|
||||
// marker.points.push_back(p);
|
||||
// marker.header.stamp = ros::Time::now();
|
||||
// marker_pub.publish(marker);
|
||||
|
||||
explored.insert(current_node);
|
||||
const double current_cost_to_come = cost_to_come.at(current_node);
|
||||
|
||||
// Expand the node to find all neighbours, adding them to the frontier if we have not already explored them
|
||||
const auto neighbours = neighbour_fn(current_node);
|
||||
|
||||
// neighbours_marker.points = EigenHelpersConversions::VectorEigenVector3dToVectorGeometryPoint(neighbours);
|
||||
// neighbours_marker.header.stamp = ros::Time::now();
|
||||
// marker_pub.publish(neighbours_marker);
|
||||
// std::cout << std::flush;
|
||||
|
||||
for (const auto neighbour : neighbours)
|
||||
{
|
||||
// Check if we've already explored this neighbour
|
||||
if (explored.find(neighbour) != explored.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do some sanity checks so that we can make assumptions later
|
||||
const auto neighbour_cost_to_come_ittr = cost_to_come.find(neighbour);
|
||||
const auto neighbour_backpointer_ittr = backpointers.find(neighbour);
|
||||
if (neighbour_cost_to_come_ittr == cost_to_come.end())
|
||||
{
|
||||
assert(neighbour_backpointer_ittr == backpointers.end());
|
||||
}
|
||||
if (neighbour_backpointer_ittr == backpointers.end())
|
||||
{
|
||||
assert(neighbour_cost_to_come_ittr == cost_to_come.end());
|
||||
}
|
||||
|
||||
// If we haven't already explored this neighbour, see if we've found a cheaper path
|
||||
const double neighbour_new_cost_to_come = current_cost_to_come + distance_fn(current_node, neighbour);
|
||||
if (neighbour_cost_to_come_ittr != cost_to_come.end() && neighbour_cost_to_come_ittr->second <= neighbour_new_cost_to_come)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
frontier.push(ConfigAndDistType(neighbour, neighbour_new_cost_to_come + heuristic_fn(neighbour)));
|
||||
cost_to_come[neighbour] = neighbour_new_cost_to_come;
|
||||
backpointers[neighbour] = current_node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "Already explored this node, skipping\n";
|
||||
}
|
||||
}
|
||||
|
||||
const auto end_time = std::chrono::steady_clock::now();
|
||||
results.second["planning time"] = std::chrono::duration<double>(end_time - start_time).count();
|
||||
results.second["nodes explored"] = explored.size();
|
||||
|
||||
return results;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SIMPLE_ASTAR_PLANNER_HPP
|
||||
117
flightlib/third_party/arc_utilities/include/arc_utilities/simple_dtw.hpp
vendored
Normal file
117
flightlib/third_party/arc_utilities/include/arc_utilities/simple_dtw.hpp
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#ifndef SIMPLE_DTW_HPP
|
||||
#define SIMPLE_DTW_HPP
|
||||
|
||||
namespace simple_dtw
|
||||
{
|
||||
template<typename FirstDatatype, typename SecondDatatype, typename DistanceFn,
|
||||
typename FirstAllocator = std::allocator<FirstDatatype>,
|
||||
typename SecondAllocator = std::allocator<SecondDatatype>>
|
||||
class SimpleDTW
|
||||
{
|
||||
private:
|
||||
|
||||
void InitializeMatrix(const size_t first_sequence_size, const size_t second_sequence_size)
|
||||
{
|
||||
const ssize_t rows = (ssize_t)first_sequence_size + 1;
|
||||
const ssize_t cols = (ssize_t)second_sequence_size + 1;
|
||||
if (dtw_matrix_.rows() < rows || dtw_matrix_.cols() < cols)
|
||||
{
|
||||
dtw_matrix_ = Eigen::MatrixXd::Zero(rows, cols);
|
||||
if (rows > 1 && cols > 1)
|
||||
{
|
||||
for (ssize_t row = 1; row < rows; row++)
|
||||
{
|
||||
dtw_matrix_(row, 0) = std::numeric_limits<double>::infinity();
|
||||
}
|
||||
for (ssize_t col = 1; col < cols; col++)
|
||||
{
|
||||
dtw_matrix_(0, col) = std::numeric_limits<double>::infinity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Eigen::MatrixXd dtw_matrix_;
|
||||
|
||||
public:
|
||||
|
||||
SimpleDTW()
|
||||
{
|
||||
InitializeMatrix(0, 0);
|
||||
}
|
||||
|
||||
SimpleDTW(const size_t first_sequence_size, const size_t second_sequence_size)
|
||||
{
|
||||
InitializeMatrix(first_sequence_size, second_sequence_size);
|
||||
}
|
||||
|
||||
double EvaluateWarpingCost(
|
||||
const std::vector<FirstDatatype, FirstAllocator>& first_sequence,
|
||||
const std::vector<SecondDatatype, SecondAllocator>& second_sequence,
|
||||
const DistanceFn& distance_fn)
|
||||
{
|
||||
InitializeMatrix(first_sequence.size(), second_sequence.size());
|
||||
//Compute DTW cost for the two sequences
|
||||
for (ssize_t i = 1; i <= (ssize_t)first_sequence.size(); i++)
|
||||
{
|
||||
const FirstDatatype& first_item = first_sequence[(size_t)i - 1];
|
||||
for (ssize_t j = 1; j <= (ssize_t)second_sequence.size(); j++)
|
||||
{
|
||||
const SecondDatatype& second_item = second_sequence[(size_t)j - 1];
|
||||
const double index_cost = distance_fn(first_item, second_item);
|
||||
double prev_cost = 0.0;
|
||||
// Get the three neighboring values from the matrix to use for the update
|
||||
double im1j = dtw_matrix_(i - 1, j);
|
||||
double im1jm1 = dtw_matrix_(i - 1, j - 1);
|
||||
double ijm1 = dtw_matrix_(i, j - 1);
|
||||
// Start the update step
|
||||
if (im1j < im1jm1 && im1j < ijm1)
|
||||
{
|
||||
prev_cost = im1j;
|
||||
}
|
||||
else if (ijm1 < im1j && ijm1 < im1jm1)
|
||||
{
|
||||
prev_cost = ijm1;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_cost = im1jm1;
|
||||
}
|
||||
// Update the value in the matrix
|
||||
const double new_cost = index_cost + prev_cost;
|
||||
dtw_matrix_(i, j) = new_cost;
|
||||
}
|
||||
}
|
||||
//Return total path cost
|
||||
const double warping_cost = dtw_matrix_((ssize_t)first_sequence.size(), (ssize_t)second_sequence.size());
|
||||
return warping_cost;
|
||||
}
|
||||
};
|
||||
|
||||
// DistanceFn must match the prototype std::function<double(const FirstDataype&, const SecondDatatype&)>
|
||||
template<typename FirstDatatype, typename SecondDatatype, typename DistanceFn,
|
||||
typename FirstAllocator = std::allocator<FirstDatatype>,
|
||||
typename SecondAllocator = std::allocator<SecondDatatype>>
|
||||
inline double ComputeDTWDistance(
|
||||
const std::vector<FirstDatatype, FirstAllocator>& first_sequence,
|
||||
const std::vector<SecondDatatype, SecondAllocator>& second_sequence,
|
||||
const DistanceFn& distance_fn)
|
||||
{
|
||||
SimpleDTW<FirstDatatype, SecondDatatype, DistanceFn, FirstAllocator, SecondAllocator> dtw_evaluator;
|
||||
return dtw_evaluator.EvaluateWarpingCost(first_sequence, second_sequence, distance_fn);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SIMPLE_DTW_HPP
|
||||
95
flightlib/third_party/arc_utilities/include/arc_utilities/simple_hausdorff_distance.hpp
vendored
Normal file
95
flightlib/third_party/arc_utilities/include/arc_utilities/simple_hausdorff_distance.hpp
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#ifdef ENABLE_PARALLEL_HAUSDORFF_DISTANCE
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#ifndef SIMPLE_HAUSDORFF_DISTANCE_HPP
|
||||
#define SIMPLE_HAUSDORFF_DISTANCE_HPP
|
||||
|
||||
namespace simple_hausdorff_distance
|
||||
{
|
||||
class SimpleHausdorffDistance
|
||||
{
|
||||
private:
|
||||
|
||||
SimpleHausdorffDistance() {}
|
||||
|
||||
static inline size_t GetNumOMPThreads(void)
|
||||
{
|
||||
#ifdef ENABLE_PARALLEL_HAUSDORFF_DISTANCE
|
||||
#if defined(_OPENMP)
|
||||
size_t num_threads = 0;
|
||||
#pragma omp parallel
|
||||
{
|
||||
num_threads = (size_t)omp_get_num_threads();
|
||||
}
|
||||
return num_threads;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename FirstDatatype, typename SecondDatatype, typename FirstAllocator=std::allocator<FirstDatatype>, typename SecondAllocator=std::allocator<SecondDatatype>>
|
||||
static double ComputeDistance(const std::vector<FirstDatatype, FirstAllocator>& first_distribution, const std::vector<SecondDatatype, SecondAllocator>& second_distribution, const std::function<double(const FirstDatatype&, const SecondDatatype&)>& distance_fn)
|
||||
{
|
||||
// Compute the Hausdorff distance - the "maximum minimum" distance
|
||||
std::vector<double> per_thread_storage(GetNumOMPThreads(), 0.0);
|
||||
#ifdef ENABLE_PARALLEL_HAUSDORFF_DISTANCE
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (size_t idx = 0; idx < first_distribution.size(); idx++)
|
||||
{
|
||||
const FirstDatatype& first = first_distribution[idx];
|
||||
double minimum_distance = INFINITY;
|
||||
for (size_t jdx = 0; jdx < second_distribution.size(); jdx++)
|
||||
{
|
||||
const SecondDatatype& second = second_distribution[jdx];
|
||||
const double current_distance = distance_fn(first, second);
|
||||
if (current_distance < minimum_distance)
|
||||
{
|
||||
minimum_distance = current_distance;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PARALLEL_HAUSDORFF_DISTANCE
|
||||
#if defined(_OPENMP)
|
||||
const size_t current_thread_id = (size_t)omp_get_thread_num();
|
||||
#else
|
||||
const size_t current_thread_id = 0;
|
||||
#endif
|
||||
#else
|
||||
const size_t current_thread_id = 0;
|
||||
#endif
|
||||
if (minimum_distance > per_thread_storage[current_thread_id])
|
||||
{
|
||||
per_thread_storage[current_thread_id] = minimum_distance;
|
||||
}
|
||||
}
|
||||
double maximum_minimum_distance = 0.0;
|
||||
for (size_t idx = 0; idx < per_thread_storage.size(); idx++)
|
||||
{
|
||||
const double temp_minimum_distance = per_thread_storage[idx];
|
||||
if (temp_minimum_distance > maximum_minimum_distance)
|
||||
{
|
||||
maximum_minimum_distance = temp_minimum_distance;
|
||||
}
|
||||
}
|
||||
return maximum_minimum_distance;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // SIMPLE_HAUSDORFF_DISTANCE_HPP
|
||||
378
flightlib/third_party/arc_utilities/include/arc_utilities/simple_hierarchical_clustering.hpp
vendored
Normal file
378
flightlib/third_party/arc_utilities/include/arc_utilities/simple_hierarchical_clustering.hpp
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#ifndef SIMPLE_HIERARCHICAL_CLUSTERING_HPP
|
||||
#define SIMPLE_HIERARCHICAL_CLUSTERING_HPP
|
||||
|
||||
namespace simple_hierarchical_clustering
|
||||
{
|
||||
class SimpleHierarchicalClustering
|
||||
{
|
||||
private:
|
||||
|
||||
SimpleHierarchicalClustering() {}
|
||||
|
||||
static inline size_t GetNumOMPThreads()
|
||||
{
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
size_t num_threads = 0;
|
||||
#pragma omp parallel
|
||||
{
|
||||
num_threads = (size_t)omp_get_num_threads();
|
||||
}
|
||||
return num_threads;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::pair<std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>>, double> GetClosestPair(const std::vector<uint8_t>& datapoint_mask, const Eigen::MatrixXd& distance_matrix, const std::vector<std::vector<int64_t>>& clusters)
|
||||
{
|
||||
// Compute distances between unclustered points <-> unclustered points, unclustered_points <-> clusters, and clusters <-> clusters
|
||||
// Compute the minimum unclustered point <-> unclustered point / unclustered_point <-> cluster distance
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
const size_t num_threads = GetNumOMPThreads();
|
||||
std::vector<double> per_thread_min_distances(num_threads, INFINITY);
|
||||
std::vector<std::pair<int64_t, std::pair<bool, int64_t>>> per_thread_min_element_pairs(num_threads, std::make_pair(-1, std::make_pair(false, -1)));
|
||||
#pragma omp parallel for
|
||||
#else
|
||||
double min_distance = INFINITY;
|
||||
std::pair<int64_t, std::pair<bool, int64_t>> min_element_pair(-1, std::pair<bool, int64_t>(false, -1));
|
||||
#endif
|
||||
for (size_t idx = 0; idx < datapoint_mask.size(); idx++)
|
||||
{
|
||||
// Make sure we aren't in a cluster already
|
||||
if (datapoint_mask[idx] == 0)
|
||||
{
|
||||
// Compute the minimum unclustered point <-> unclustered point distance
|
||||
double min_point_point_distance = INFINITY;
|
||||
int64_t min_point_index = -1;
|
||||
for (size_t jdx = 0; jdx < datapoint_mask.size(); jdx++)
|
||||
{
|
||||
// Make sure the other point isn't us, and isn't already in a cluster
|
||||
if ((idx != jdx) && (datapoint_mask[jdx] == 0))
|
||||
{
|
||||
const double& current_distance = distance_matrix((ssize_t)idx, (ssize_t)jdx);
|
||||
// Update the closest point
|
||||
if (current_distance < min_point_point_distance)
|
||||
{
|
||||
min_point_point_distance = current_distance;
|
||||
min_point_index = (int64_t)jdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Compute the minimum unclustered point <-> cluster distance
|
||||
double min_point_cluster_distance = INFINITY;
|
||||
int64_t min_cluster_index = -1;
|
||||
for (size_t cdx = 0; cdx < clusters.size(); cdx++)
|
||||
{
|
||||
// We only work with clusters that aren't empty
|
||||
if (clusters[cdx].size() > 0)
|
||||
{
|
||||
// Compute the distance to the current cluster
|
||||
double current_distance = 0.0;
|
||||
for (size_t cpdx = 0; cpdx < clusters[cdx].size(); cpdx++)
|
||||
{
|
||||
const int64_t& current_cluster_point_index = clusters[cdx][cpdx];
|
||||
const double& new_distance = distance_matrix((ssize_t)idx, (ssize_t)current_cluster_point_index);
|
||||
if (new_distance > current_distance)
|
||||
{
|
||||
current_distance = new_distance;
|
||||
}
|
||||
}
|
||||
// Update the closest cluster
|
||||
if (current_distance < min_point_cluster_distance)
|
||||
{
|
||||
min_point_cluster_distance = current_distance;
|
||||
min_cluster_index = (int64_t)cdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
const size_t thread_num = (size_t)omp_get_thread_num();
|
||||
double& per_thread_min_distance = per_thread_min_distances[thread_num];
|
||||
std::pair<int64_t, std::pair<bool, int64_t>>& per_thread_min_element_pair = per_thread_min_element_pairs[thread_num];
|
||||
// Update the closest index
|
||||
if (min_point_point_distance < per_thread_min_distance)
|
||||
{
|
||||
per_thread_min_distance = min_point_point_distance;
|
||||
per_thread_min_element_pair.first = idx;
|
||||
per_thread_min_element_pair.second.first = false;
|
||||
per_thread_min_element_pair.second.second = min_point_index;
|
||||
}
|
||||
if (min_point_cluster_distance < per_thread_min_distance)
|
||||
{
|
||||
per_thread_min_distance = min_point_cluster_distance;
|
||||
per_thread_min_element_pair.first = idx;
|
||||
per_thread_min_element_pair.second.first = true;
|
||||
per_thread_min_element_pair.second.second = min_cluster_index;
|
||||
}
|
||||
#else
|
||||
// Update the closest index
|
||||
if (min_point_point_distance < min_distance)
|
||||
{
|
||||
min_distance = min_point_point_distance;
|
||||
min_element_pair.first = (int64_t)idx;
|
||||
min_element_pair.second.first = false;
|
||||
min_element_pair.second.second = min_point_index;
|
||||
}
|
||||
if (min_point_cluster_distance < min_distance)
|
||||
{
|
||||
min_distance = min_point_cluster_distance;
|
||||
min_element_pair.first = (int64_t)idx;
|
||||
min_element_pair.second.first = true;
|
||||
min_element_pair.second.second = min_cluster_index;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
double min_distance = INFINITY;
|
||||
std::pair<int64_t, std::pair<bool, int64_t>> min_element_pair(-1, std::pair<bool, int64_t>(false, -1));
|
||||
for (size_t idx = 0; idx < num_threads; idx++)
|
||||
{
|
||||
const double& current_min_distance = per_thread_min_distances[idx];
|
||||
const std::pair<int64_t, std::pair<bool, int64_t>>& current_min_element_pair = per_thread_min_element_pairs[idx];
|
||||
if (current_min_distance < min_distance)
|
||||
{
|
||||
min_distance = current_min_distance;
|
||||
min_element_pair = current_min_element_pair;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Compute the minimum cluster <-> cluster distance
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
std::vector<double> per_thread_min_cluster_cluster_distances(num_threads, INFINITY);
|
||||
std::vector<std::pair<int64_t, int64_t>> per_thread_min_cluster_pairs(num_threads, std::make_pair(-1, -1));
|
||||
#pragma omp parallel for
|
||||
#else
|
||||
double min_cluster_cluster_distance = INFINITY;
|
||||
std::pair<int64_t, int64_t> min_cluster_pair(-1, -1);
|
||||
#endif
|
||||
for (size_t fcdx = 0; fcdx < clusters.size(); fcdx++)
|
||||
{
|
||||
const std::vector<int64_t>& first_cluster = clusters[fcdx];
|
||||
// Don't evaluate empty clusters
|
||||
if (first_cluster.size() > 0)
|
||||
{
|
||||
for (size_t scdx = 0; scdx < clusters.size(); scdx++)
|
||||
{
|
||||
// Don't compare against ourself
|
||||
if (fcdx != scdx)
|
||||
{
|
||||
const std::vector<int64_t>& second_cluster = clusters[scdx];
|
||||
// Don't evaluate empty clusters
|
||||
if (second_cluster.size() > 0)
|
||||
{
|
||||
// Compute the cluster <-> cluster distance
|
||||
double max_point_point_distance = 0.0;
|
||||
// Find the maximum-pointwise distance between clusters
|
||||
for (size_t fcpx = 0; fcpx < first_cluster.size(); fcpx++)
|
||||
{
|
||||
const int64_t& fcp_index = first_cluster[fcpx];
|
||||
for (size_t scpx = 0; scpx < second_cluster.size(); scpx++)
|
||||
{
|
||||
const int64_t& scp_index = second_cluster[scpx];
|
||||
const double& new_distance = distance_matrix(fcp_index, scp_index);
|
||||
if (new_distance > max_point_point_distance)
|
||||
{
|
||||
max_point_point_distance = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
const double cluster_cluster_distance = max_point_point_distance;
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
const size_t thread_num = (size_t)omp_get_thread_num();
|
||||
double& per_thread_min_cluster_cluster_distance = per_thread_min_cluster_cluster_distances[thread_num];
|
||||
std::pair<int64_t, int64_t>& per_thread_min_cluster_pair = per_thread_min_cluster_pairs[thread_num];
|
||||
if (cluster_cluster_distance < per_thread_min_cluster_cluster_distance)
|
||||
{
|
||||
per_thread_min_cluster_cluster_distance = cluster_cluster_distance;
|
||||
per_thread_min_cluster_pair.first = fcdx;
|
||||
per_thread_min_cluster_pair.second = scdx;
|
||||
}
|
||||
#else
|
||||
if (cluster_cluster_distance < min_cluster_cluster_distance)
|
||||
{
|
||||
min_cluster_cluster_distance = cluster_cluster_distance;
|
||||
min_cluster_pair.first = (int64_t)fcdx;
|
||||
min_cluster_pair.second = (int64_t)scdx;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PARALLEL_COMPLETE_LINK_CLUSTERING
|
||||
double min_cluster_cluster_distance = INFINITY;
|
||||
std::pair<int64_t, int64_t> min_cluster_pair(-1, -1);
|
||||
for (size_t idx = 0; idx < num_threads; idx++)
|
||||
{
|
||||
const double& current_min_cluster_cluster_distance = per_thread_min_cluster_cluster_distances[idx];
|
||||
const std::pair<int64_t, int64_t>& current_min_cluster_pair = per_thread_min_cluster_pairs[idx];
|
||||
if (current_min_cluster_cluster_distance < min_cluster_cluster_distance)
|
||||
{
|
||||
min_cluster_cluster_distance = current_min_cluster_cluster_distance;
|
||||
min_cluster_pair = current_min_cluster_pair;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Return the minimum-distance pair
|
||||
if (min_distance < min_cluster_cluster_distance)
|
||||
{
|
||||
// Set the indices
|
||||
const std::pair<bool, int64_t> first_index(false, min_element_pair.first);
|
||||
const std::pair<bool, int64_t> second_index = min_element_pair.second;
|
||||
const std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>> indices(first_index, second_index);
|
||||
const std::pair<std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>>, double> minimum_pair(indices, min_distance);
|
||||
return minimum_pair;
|
||||
}
|
||||
// A cluster <-> cluster pair is closest
|
||||
else
|
||||
{
|
||||
// Set the indices
|
||||
const std::pair<bool, int64_t> first_index(true, min_cluster_pair.first);
|
||||
const std::pair<bool, int64_t> second_index(true, min_cluster_pair.second);
|
||||
const std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>> indices(first_index, second_index);
|
||||
const std::pair<std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>>, double> minimum_pair(indices, min_cluster_cluster_distance);
|
||||
return minimum_pair;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename Datatype, typename Allocator=std::allocator<Datatype>>
|
||||
static std::pair<std::vector<std::vector<Datatype, Allocator>>, double> Cluster(const std::vector<Datatype, Allocator>& data, const std::function<double(const Datatype&, const Datatype&)>& distance_fn, const double max_cluster_distance)
|
||||
{
|
||||
const Eigen::MatrixXd distance_matrix = arc_helpers::BuildDistanceMatrix(data, distance_fn);
|
||||
return Cluster(data, distance_matrix, max_cluster_distance);
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator=std::allocator<Datatype>>
|
||||
static std::pair<std::vector<std::vector<Datatype, Allocator>>, double> Cluster(const std::vector<Datatype, Allocator>& data, const Eigen::MatrixXd& distance_matrix, const double max_cluster_distance)
|
||||
{
|
||||
assert((size_t)distance_matrix.rows() == data.size());
|
||||
assert((size_t)distance_matrix.cols() == data.size());
|
||||
std::vector<uint8_t> datapoint_mask(data.size(), 0u);
|
||||
std::vector<std::vector<int64_t>> cluster_indices;
|
||||
double closest_distance = 0.0;
|
||||
bool complete = false;
|
||||
while (!complete)
|
||||
{
|
||||
// Get closest pair of elements (an element can be a cluster or single data value!)
|
||||
const std::pair<std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>>, double> closest_element_pair = GetClosestPair(datapoint_mask, distance_matrix, cluster_indices);
|
||||
const std::pair<std::pair<bool, int64_t>, std::pair<bool, int64_t>>& closest_elements = closest_element_pair.first;
|
||||
closest_distance = closest_element_pair.second;
|
||||
//std::cout << "Element pair: " << PrettyPrint::PrettyPrint(closest_element_pair, true) << std::endl;
|
||||
if (closest_distance <= max_cluster_distance)
|
||||
{
|
||||
const std::pair<bool, int64_t>& first_element = closest_elements.first;
|
||||
const std::pair<bool, int64_t>& second_element = closest_elements.second;
|
||||
// If both elements are points, create a new cluster
|
||||
if ((first_element.first == false) && (second_element.first == false))
|
||||
{
|
||||
//std::cout << "New point-point cluster" << std::endl;
|
||||
const int64_t first_element_index = first_element.second;
|
||||
assert(first_element_index >= 0);
|
||||
const int64_t second_element_index = second_element.second;
|
||||
assert(second_element_index >= 0);
|
||||
// Add a cluster
|
||||
cluster_indices.push_back(std::vector<int64_t>{first_element_index, second_element_index});
|
||||
// Mask out the indices
|
||||
datapoint_mask[(size_t)first_element_index] = 1u;
|
||||
datapoint_mask[(size_t)second_element_index] = 1u;
|
||||
}
|
||||
// If both elements are clusters, merge the clusters
|
||||
else if ((first_element.first == true) && (second_element.first == true))
|
||||
{
|
||||
//std::cout << "Combining clusters" << std::endl;
|
||||
// Get the cluster indices
|
||||
const int64_t first_cluster_index = first_element.second;
|
||||
assert(first_cluster_index >= 0);
|
||||
const int64_t second_cluster_index = second_element.second;
|
||||
assert(second_cluster_index >= 0);
|
||||
// Merge the second cluster into the first
|
||||
std::vector<int64_t>& first_cluster = cluster_indices[(size_t)first_cluster_index];
|
||||
std::vector<int64_t>& second_cluster = cluster_indices[(size_t)second_cluster_index];
|
||||
first_cluster.insert(first_cluster.end(), second_cluster.begin(), second_cluster.end());
|
||||
// Empty the second cluster (we don't remove, because this triggers move)
|
||||
second_cluster.clear();
|
||||
}
|
||||
// If one of the elements is a cluster and the other is a point, add the point to the existing cluster
|
||||
else
|
||||
{
|
||||
//std::cout << "Adding to an existing cluster" << std::endl;
|
||||
int64_t cluster_index = -1;
|
||||
int64_t element_index = -1;
|
||||
if (first_element.first)
|
||||
{
|
||||
cluster_index = first_element.second;
|
||||
element_index = second_element.second;
|
||||
}
|
||||
else if (second_element.first)
|
||||
{
|
||||
cluster_index = second_element.second;
|
||||
element_index = first_element.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
assert(cluster_index >= 0);
|
||||
assert(element_index >= 0);
|
||||
// Add the element to the cluster
|
||||
std::vector<int64_t>& cluster = cluster_indices[(size_t)cluster_index];
|
||||
cluster.push_back(element_index);
|
||||
// Mask out the element index
|
||||
datapoint_mask[(size_t)element_index] = 1u;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
// Extract the actual cluster data
|
||||
std::vector<std::vector<Datatype, Allocator>> clusters;
|
||||
for (size_t idx = 0; idx < cluster_indices.size(); idx++)
|
||||
{
|
||||
const std::vector<int64_t>& current_cluster = cluster_indices[idx];
|
||||
// Ignore empty clusters
|
||||
if (current_cluster.size() > 0)
|
||||
{
|
||||
std::vector<Datatype, Allocator> new_cluster;
|
||||
for (size_t cdx = 0; cdx < current_cluster.size(); cdx++)
|
||||
{
|
||||
const int64_t index = current_cluster[cdx];
|
||||
new_cluster.push_back(data[(size_t)index]);
|
||||
}
|
||||
clusters.push_back(new_cluster);
|
||||
}
|
||||
}
|
||||
// Add any points that we haven't clustered into their own clusters
|
||||
for (size_t idx = 0; idx < datapoint_mask.size(); idx++)
|
||||
{
|
||||
// If an element hasn't been clustered at all
|
||||
if (datapoint_mask[idx] == 0)
|
||||
{
|
||||
clusters.push_back(std::vector<Datatype, Allocator>{data[idx]});
|
||||
}
|
||||
}
|
||||
return std::pair<std::vector<std::vector<Datatype, Allocator>>, double>(clusters, closest_distance);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // SIMPLE_HIERARCHICAL_CLUSTERING_HPP
|
||||
398
flightlib/third_party/arc_utilities/include/arc_utilities/simple_kmeans_clustering.hpp
vendored
Normal file
398
flightlib/third_party/arc_utilities/include/arc_utilities/simple_kmeans_clustering.hpp
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#ifndef SIMPLE_KMEANS_CLUSTERING_HPP
|
||||
#define SIMPLE_KMEANS_CLUSTERING_HPP
|
||||
|
||||
namespace simple_kmeans_clustering
|
||||
{
|
||||
class SimpleKMeansClustering
|
||||
{
|
||||
private:
|
||||
|
||||
SimpleKMeansClustering() {}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static uint32_t GetClosestCluster(
|
||||
const Datatype& datapoint,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::vector<Datatype, Allocator>& cluster_centers)
|
||||
{
|
||||
int64_t best_label = -1;
|
||||
double best_distance = INFINITY;
|
||||
for (size_t cluster = 0; cluster < cluster_centers.size(); cluster++)
|
||||
{
|
||||
const Datatype& cluster_center = cluster_centers[cluster];
|
||||
const double distance = distance_fn(cluster_center, datapoint);
|
||||
if (distance < best_distance)
|
||||
{
|
||||
best_distance = distance;
|
||||
best_label = (int64_t)cluster;
|
||||
}
|
||||
}
|
||||
assert(best_label >= 0);
|
||||
return (uint32_t)best_label;
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::vector<uint32_t> PerformSingleClusteringIteration(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::vector<Datatype, Allocator>& cluster_centers)
|
||||
{
|
||||
std::vector<uint32_t> cluster_labels(data.size());
|
||||
for (size_t idx = 0; idx < data.size(); idx++)
|
||||
{
|
||||
const Datatype& datapoint = data[idx];
|
||||
const uint32_t label = GetClosestCluster(datapoint, distance_fn, cluster_centers);
|
||||
cluster_labels[idx] = label;
|
||||
}
|
||||
return cluster_labels;
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::vector<Datatype, Allocator> ComputeClusterCenters(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::vector<uint32_t>& cluster_labels,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&)>& average_fn,
|
||||
const uint32_t num_clusters)
|
||||
{
|
||||
assert(data.size() == cluster_labels.size());
|
||||
|
||||
// Separate the datapoints into their clusters
|
||||
std::vector<std::vector<Datatype, Allocator>> clustered_data(num_clusters);
|
||||
for (size_t idx = 0; idx < data.size(); idx++)
|
||||
{
|
||||
const Datatype& datapoint = data[idx];
|
||||
const uint32_t label = cluster_labels[idx];
|
||||
clustered_data[label].push_back(datapoint);
|
||||
}
|
||||
|
||||
// Compute the center of each cluster
|
||||
std::vector<Datatype, Allocator> cluster_centers(num_clusters);
|
||||
for (uint32_t cluster = 0; cluster < num_clusters; cluster++)
|
||||
{
|
||||
const std::vector<Datatype, Allocator>& cluster_data = clustered_data[cluster];
|
||||
cluster_centers[cluster] = average_fn(cluster_data);
|
||||
}
|
||||
return cluster_centers;
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::vector<Datatype, Allocator> ComputeClusterCentersWeighted(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::vector<double>& weights,
|
||||
const std::vector<uint32_t>& cluster_labels,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&, const std::vector<double>&)>& average_fn,
|
||||
const uint32_t num_clusters)
|
||||
{
|
||||
assert(data.size() == cluster_labels.size());
|
||||
|
||||
// Separate the datapoints into their clusters
|
||||
std::vector<std::vector<Datatype, Allocator>> clustered_data(num_clusters);
|
||||
std::vector<std::vector<double>> clustered_weights(num_clusters);
|
||||
for (size_t idx = 0; idx < data.size(); idx++)
|
||||
{
|
||||
const Datatype& datapoint = data[idx];
|
||||
const double weight = weights[idx];
|
||||
const uint32_t label = cluster_labels[idx];
|
||||
|
||||
clustered_data[label].push_back(datapoint);
|
||||
clustered_weights[label].push_back(weight);
|
||||
}
|
||||
|
||||
// Compute the center of each cluster
|
||||
std::vector<Datatype, Allocator> cluster_centers(num_clusters);
|
||||
for (uint32_t cluster = 0; cluster < num_clusters; cluster++)
|
||||
{
|
||||
const std::vector<Datatype, Allocator>& cluster_data = clustered_data[cluster];
|
||||
const std::vector<double>& cluster_weights = clustered_weights[cluster];
|
||||
cluster_centers[cluster] = average_fn(cluster_data, cluster_weights);
|
||||
}
|
||||
return cluster_centers;
|
||||
}
|
||||
|
||||
static bool CheckForConvergence(
|
||||
const std::vector<uint32_t>& old_labels,
|
||||
const std::vector<uint32_t>& new_labels)
|
||||
{
|
||||
assert(old_labels.size() == new_labels.size());
|
||||
for (size_t idx = 0; idx < old_labels.size(); idx++)
|
||||
{
|
||||
const uint32_t old_label = old_labels[idx];
|
||||
const uint32_t new_label = new_labels[idx];
|
||||
if (old_label != new_label)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::pair<std::vector<uint32_t>, std::vector<Datatype, Allocator>> Cluster(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&)>& average_fn,
|
||||
std::vector<Datatype, Allocator> cluster_centers)
|
||||
{
|
||||
const uint32_t num_clusters = cluster_centers.size();
|
||||
assert(num_clusters < std::numeric_limits<uint32_t>::max());
|
||||
|
||||
// Run the first iteration of clustering
|
||||
std::vector<uint32_t> cluster_labels = PerformSingleClusteringIteration(data, distance_fn, cluster_centers);
|
||||
|
||||
// Itterate until converged
|
||||
bool converged = false;
|
||||
uint32_t iteration = 1u;
|
||||
while (!converged)
|
||||
{
|
||||
// Update cluster centers
|
||||
cluster_centers = ComputeClusterCenters(data, cluster_labels, average_fn, num_clusters);
|
||||
// Cluster with the new centers
|
||||
std::vector<uint32_t> new_cluster_labels = PerformSingleClusteringIteration(data, distance_fn, cluster_centers);
|
||||
// Check for convergence
|
||||
converged = CheckForConvergence(cluster_labels, new_cluster_labels);
|
||||
cluster_labels = new_cluster_labels;
|
||||
iteration++;
|
||||
}
|
||||
std::cerr << "[K-means clustering] Clustering converged after " << iteration << " iterations" << std::endl;
|
||||
return std::make_pair(cluster_labels, cluster_centers);
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::vector<uint32_t> Cluster(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&)>& average_fn,
|
||||
const uint32_t num_clusters,
|
||||
const bool do_preliminary_clustering = false)
|
||||
{
|
||||
assert(data.size() > 0);
|
||||
assert(num_clusters > 0);
|
||||
|
||||
if (num_clusters == 1)
|
||||
{
|
||||
std::cerr << "[K-means clustering] Provided num_clusters = 1, returning default labels for cluster 0" << std::endl;
|
||||
return std::vector<uint32_t>(data.size(), 0u);
|
||||
}
|
||||
|
||||
// Prepare an RNG for cluster initialization
|
||||
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
std::mt19937_64 prng(seed);
|
||||
std::uniform_int_distribution<size_t> initialization_distribution(0u, data.size() - 1);
|
||||
// Initialize cluster centers
|
||||
std::vector<Datatype, Allocator> cluster_centers;
|
||||
|
||||
// Make sure we have enough datapoints to do meaningful preliminary clustering
|
||||
bool enable_preliminary_clustering = do_preliminary_clustering;
|
||||
if (enable_preliminary_clustering)
|
||||
{
|
||||
const size_t subset_size = (size_t)ceil((double)data.size() * 0.1);
|
||||
if (subset_size >= (num_clusters * 5))
|
||||
{
|
||||
enable_preliminary_clustering = true;
|
||||
std::cerr << "[K-means clustering] Preliminary clustering enabled, using subset of " << subset_size << " datapoints from " << data.size() << " total" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_preliminary_clustering = false;
|
||||
std::cerr << "[K-means clustering] Preliminary clustering disabled as input data is too small w.r.t. number of clusters" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_preliminary_clustering)
|
||||
{
|
||||
// Select a random 10% of the input data
|
||||
const size_t subset_size = (size_t)ceil((double)data.size() * 0.1);
|
||||
// This makes sure we don't get duplicates
|
||||
std::map<size_t, uint8_t> index_map;
|
||||
while (index_map.size() < subset_size)
|
||||
{
|
||||
const size_t random_index = initialization_distribution(prng);
|
||||
index_map[random_index] = 1u;
|
||||
}
|
||||
std::vector<Datatype, Allocator> random_subset;
|
||||
random_subset.reserve(subset_size);
|
||||
for (auto itr = index_map.begin(); itr != index_map.end(); ++itr)
|
||||
{
|
||||
if (itr->second == 1u)
|
||||
{
|
||||
const size_t random_index = itr->first;
|
||||
const Datatype& random_element = data[random_index];
|
||||
random_subset.push_back(random_element);
|
||||
}
|
||||
}
|
||||
assert(random_subset.size() == subset_size);
|
||||
// Run clustering on the subset
|
||||
std::vector<uint32_t> random_subset_labels = Cluster(random_subset, distance_fn, average_fn, num_clusters, false);
|
||||
// Now we use the centers of the clusters to form the cluster centers
|
||||
cluster_centers = ComputeClusterCenters(random_subset, random_subset_labels, average_fn, num_clusters);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This makes sure we don't get duplicates
|
||||
std::map<size_t, uint8_t> index_map;
|
||||
while (index_map.size() < num_clusters)
|
||||
{
|
||||
const size_t random_index = initialization_distribution(prng);
|
||||
index_map[random_index] = 1u;
|
||||
}
|
||||
cluster_centers.reserve(num_clusters);
|
||||
for (auto itr = index_map.begin(); itr != index_map.end(); ++itr)
|
||||
{
|
||||
if (itr->second == 1u)
|
||||
{
|
||||
const size_t random_index = itr->first;
|
||||
const Datatype& random_element = data[random_index];
|
||||
cluster_centers.push_back(random_element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(cluster_centers.size() == num_clusters);
|
||||
return Cluster(data, distance_fn, average_fn, cluster_centers).first;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::pair<std::vector<uint32_t>, std::vector<Datatype, Allocator>> ClusterWeighted(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::vector<double>& weights,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&, const std::vector<double>&)>& average_fn,
|
||||
std::vector<Datatype, Allocator> cluster_centers)
|
||||
{
|
||||
const uint32_t num_clusters = cluster_centers.size();
|
||||
assert(num_clusters < std::numeric_limits<uint32_t>::max());
|
||||
|
||||
// Run the first iteration of clustering
|
||||
std::vector<uint32_t> cluster_labels = PerformSingleClusteringIteration(data, distance_fn, cluster_centers);
|
||||
|
||||
// Itterate until converged
|
||||
bool converged = false;
|
||||
uint32_t iteration = 1u;
|
||||
while (!converged)
|
||||
{
|
||||
// Update cluster centers
|
||||
cluster_centers = ComputeClusterCentersWeighted(data, weights, cluster_labels, average_fn, num_clusters);
|
||||
// Cluster with the new centers
|
||||
std::vector<uint32_t> new_cluster_labels = PerformSingleClusteringIteration(data, distance_fn, cluster_centers);
|
||||
// Check for convergence
|
||||
converged = CheckForConvergence(cluster_labels, new_cluster_labels);
|
||||
cluster_labels = new_cluster_labels;
|
||||
iteration++;
|
||||
}
|
||||
std::cerr << "[K-means clustering] Clustering converged after " << iteration << " iterations" << std::endl;
|
||||
return std::make_pair(cluster_labels, cluster_centers);
|
||||
}
|
||||
|
||||
template<typename Datatype, typename Allocator = std::allocator<Datatype>>
|
||||
static std::vector<uint32_t> ClusterWeighted(
|
||||
const std::vector<Datatype, Allocator>& data,
|
||||
const std::vector<double>& weights,
|
||||
const std::function<double(const Datatype&, const Datatype&)>& distance_fn,
|
||||
const std::function<Datatype(const std::vector<Datatype, Allocator>&, const std::vector<double>&)>& average_fn,
|
||||
const uint32_t num_clusters,
|
||||
const bool do_preliminary_clustering = false)
|
||||
{
|
||||
assert(data.size() > 0);
|
||||
assert(num_clusters > 0);
|
||||
|
||||
if (num_clusters == 1)
|
||||
{
|
||||
std::cerr << "[K-means clustering] Provided num_clusters = 1, returning default labels for cluster 0" << std::endl;
|
||||
return std::vector<uint32_t>(data.size(), 0u);
|
||||
}
|
||||
|
||||
// Prepare an RNG for cluster initialization
|
||||
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
std::mt19937_64 prng(seed);
|
||||
std::uniform_int_distribution<size_t> initialization_distribution(0u, data.size() - 1);
|
||||
// Initialize cluster centers
|
||||
std::vector<Datatype, Allocator> cluster_centers;
|
||||
|
||||
// Make sure we have enough datapoints to do meaningful preliminary clustering
|
||||
bool enable_preliminary_clustering = do_preliminary_clustering;
|
||||
if (enable_preliminary_clustering)
|
||||
{
|
||||
const size_t subset_size = (size_t)ceil((double)data.size() * 0.1);
|
||||
if (subset_size >= (num_clusters * 5))
|
||||
{
|
||||
enable_preliminary_clustering = true;
|
||||
std::cerr << "[K-means clustering] Preliminary clustering enabled, using subset of " << subset_size << " datapoints from " << data.size() << " total" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_preliminary_clustering = false;
|
||||
std::cerr << "[K-means clustering] Preliminary clustering disabled as input data is too small w.r.t. number of clusters" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_preliminary_clustering)
|
||||
{
|
||||
// Select a random 10% of the input data
|
||||
const size_t subset_size = (size_t)ceil((double)data.size() * 0.1);
|
||||
// This makes sure we don't get duplicates
|
||||
std::map<size_t, uint8_t> index_map;
|
||||
while (index_map.size() < subset_size)
|
||||
{
|
||||
const size_t random_index = initialization_distribution(prng);
|
||||
index_map[random_index] = 1u;
|
||||
}
|
||||
std::vector<Datatype, Allocator> random_subset;
|
||||
random_subset.reserve(subset_size);
|
||||
for (auto itr = index_map.begin(); itr != index_map.end(); ++itr)
|
||||
{
|
||||
if (itr->second == 1u)
|
||||
{
|
||||
const size_t random_index = itr->first;
|
||||
const Datatype& random_element = data[random_index];
|
||||
random_subset.push_back(random_element);
|
||||
}
|
||||
}
|
||||
assert(random_subset.size() == subset_size);
|
||||
// Run clustering on the subset
|
||||
std::vector<uint32_t> random_subset_labels = ClusterWeighted(random_subset, weights, distance_fn, average_fn, num_clusters, false);
|
||||
// Now we use the centers of the clusters to form the cluster centers
|
||||
cluster_centers = ComputeClusterCentersWeighted(random_subset, weights, random_subset_labels, average_fn, num_clusters);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This makes sure we don't get duplicates
|
||||
std::map<size_t, uint8_t> index_map;
|
||||
while (index_map.size() < num_clusters)
|
||||
{
|
||||
const size_t random_index = initialization_distribution(prng);
|
||||
index_map[random_index] = 1u;
|
||||
}
|
||||
cluster_centers.reserve(num_clusters);
|
||||
for (auto itr = index_map.begin(); itr != index_map.end(); ++itr)
|
||||
{
|
||||
if (itr->second == 1u)
|
||||
{
|
||||
const size_t random_index = itr->first;
|
||||
const Datatype& random_element = data[random_index];
|
||||
cluster_centers.push_back(random_element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(cluster_centers.size() == num_clusters);
|
||||
return ClusterWeighted(data, weights, distance_fn, average_fn, cluster_centers).first;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // SIMPLE_KMEANS_CLUSTERING_HPP
|
||||
450
flightlib/third_party/arc_utilities/include/arc_utilities/simple_prm_planner.hpp
vendored
Normal file
450
flightlib/third_party/arc_utilities/include/arc_utilities/simple_prm_planner.hpp
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include <omp.h>
|
||||
#ifdef ENABLE_PARALLEL_ROADMAP
|
||||
#ifndef ENABLE_PARALLEL_K_NEAREST_NEIGHBORS
|
||||
#define ENABLE_PARALLEL_K_NEAREST_NEIGHBORS
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#undef ENABLE_PARALLEL_K_NEAREST_NEIGHBORS
|
||||
#else
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#endif
|
||||
#else
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#endif
|
||||
#include <arc_utilities/dijkstras.hpp>
|
||||
|
||||
|
||||
#ifndef SIMPLE_PRM_PLANNER_HPP
|
||||
#define SIMPLE_PRM_PLANNER_HPP
|
||||
|
||||
namespace simple_prm_planner
|
||||
{
|
||||
class SimpleGeometricPrmPlanner
|
||||
{
|
||||
protected:
|
||||
|
||||
SimpleGeometricPrmPlanner() {}
|
||||
|
||||
enum NNDistanceDirection {ROADMAP_TO_NEW_STATE, NEW_STATE_TO_ROADMAP};
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static int64_t AddNodeToRoadmap(
|
||||
const T& state,
|
||||
const NNDistanceDirection nn_distance_direction,
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
// Make the node->graph or graph->node distance function as needed, then call KNN
|
||||
std::function<double(const arc_dijkstras::GraphNode<T, Allocator>&, const T&)> graph_distance_fn = nullptr;
|
||||
if (nn_distance_direction == ROADMAP_TO_NEW_STATE)
|
||||
{
|
||||
graph_distance_fn = [&] (const arc_dijkstras::GraphNode<T, Allocator>& node, const T& state)
|
||||
{
|
||||
return distance_fn(node.GetValueImmutable(), state);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
graph_distance_fn = [&] (const arc_dijkstras::GraphNode<T, Allocator>& node, const T& state)
|
||||
{
|
||||
return distance_fn(state, node.GetValueImmutable());
|
||||
};
|
||||
}
|
||||
const std::vector<std::pair<int64_t, double>> nearest_neighbors =
|
||||
arc_helpers::GetKNearestNeighbors(roadmap.GetNodesImmutable(), state, graph_distance_fn, K);
|
||||
|
||||
// Check to see this node is already in the PRM, if it is, don't re-add it, returning the existing state index
|
||||
for (const auto& nn_result : nearest_neighbors)
|
||||
{
|
||||
// If the distance is zero, check that the states are also equal
|
||||
// This allows for a psuedo-metric and not just a true metric to be used as the distance function
|
||||
if (nn_result.second == 0)
|
||||
{
|
||||
const int64_t neighbour_node_idx = nn_result.first;
|
||||
const T& neighbour_state = roadmap.GetNodeImmutable(neighbour_node_idx).GetValueImmutable();
|
||||
if (neighbour_state == state)
|
||||
{
|
||||
return neighbour_node_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new node AFTER KNN is performed
|
||||
const int64_t new_node_index = roadmap.AddNode(state);
|
||||
// Parallelize the collision-checking and distance computation
|
||||
std::vector<std::pair<double, double>> nearest_neighbors_distances(nearest_neighbors.size());
|
||||
#ifdef ENABLE_PARALLEL_ROADMAP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (size_t idx = 0; idx < nearest_neighbors.size(); idx++)
|
||||
{
|
||||
const std::pair<int64_t, double>& nearest_neighbor = nearest_neighbors[idx];
|
||||
const int64_t nearest_neighbor_index = nearest_neighbor.first;
|
||||
const double nearest_neighbor_distance = nearest_neighbor.second;
|
||||
const T& nearest_neighbor_state = roadmap.GetNodeImmutable(nearest_neighbor_index).GetValueImmutable();
|
||||
if (edge_validity_check_fn(nearest_neighbor_state, state))
|
||||
{
|
||||
if (distance_is_symmetric)
|
||||
{
|
||||
nearest_neighbors_distances[idx] = std::make_pair(nearest_neighbor_distance, nearest_neighbor_distance);
|
||||
}
|
||||
else
|
||||
{
|
||||
const double reverse_graph_distance = distance_fn(state, roadmap.GetNodeImmutable(nearest_neighbor_index).GetValueImmutable());
|
||||
if (nn_distance_direction == ROADMAP_TO_NEW_STATE)
|
||||
{
|
||||
nearest_neighbors_distances[idx] = std::make_pair(nearest_neighbor_distance, reverse_graph_distance);
|
||||
}
|
||||
else if (nn_distance_direction == ROADMAP_TO_NEW_STATE)
|
||||
{
|
||||
nearest_neighbors_distances[idx] = std::make_pair(reverse_graph_distance, nearest_neighbor_distance);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false && "This code should not be reachable");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nearest_neighbors_distances[idx] = std::make_pair(-1.0, -1.0);
|
||||
}
|
||||
}
|
||||
// THIS MUST BE SERIAL - add edges to roadmap
|
||||
for (size_t idx = 0; idx < nearest_neighbors.size(); idx++)
|
||||
{
|
||||
const std::pair<int64_t, double>& nearest_neighbor = nearest_neighbors[idx];
|
||||
const int64_t nearest_neighbor_index = nearest_neighbor.first;
|
||||
const std::pair<double, double>& nearest_neighbor_distances = nearest_neighbors_distances[idx];
|
||||
if (nearest_neighbor_distances.first >= 0.0 && nearest_neighbor_distances.second >= 0.0)
|
||||
{
|
||||
// Add the edges individually to allow for different distances in each direction
|
||||
roadmap.AddEdgeBetweenNodes(nearest_neighbor_index, new_node_index, nearest_neighbor_distances.first);
|
||||
roadmap.AddEdgeBetweenNodes(new_node_index, nearest_neighbor_index, nearest_neighbor_distances.second);
|
||||
}
|
||||
}
|
||||
return new_node_index;
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::vector<T, Allocator> ExtractSolutionPath(
|
||||
const arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::vector<int64_t>& solution_path_indices)
|
||||
{
|
||||
std::vector<T, Allocator> solution_path;
|
||||
solution_path.reserve(solution_path_indices.size());
|
||||
for (size_t idx = 0; idx < solution_path_indices.size(); idx++)
|
||||
{
|
||||
const int64_t path_index = solution_path_indices[idx];
|
||||
solution_path.push_back(roadmap.GetNodeImmutable(path_index).GetValueImmutable());
|
||||
}
|
||||
solution_path.shrink_to_fit();
|
||||
return solution_path;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static void ExtendRoadMap(
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const std::function<bool(const T&)>& state_validity_check_fn,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<bool(void)>& termination_check_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
while (!termination_check_fn())
|
||||
{
|
||||
const T random_state = sampling_fn();
|
||||
if (state_validity_check_fn(random_state))
|
||||
{
|
||||
AddNodeToRoadmap(random_state, ROADMAP_TO_NEW_STATE, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static arc_dijkstras::Graph<T, Allocator> BuildRoadMap(
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const std::function<bool(const T&)>& state_validity_check_fn,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<bool(void)>& termination_check_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
arc_dijkstras::Graph<T, Allocator> roadmap;
|
||||
ExtendRoadMap(roadmap, sampling_fn, distance_fn, state_validity_check_fn, edge_validity_check_fn, termination_check_fn, K, distance_is_symmetric);
|
||||
return roadmap;
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static void UpdateRoadMapEdges(
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn)
|
||||
{
|
||||
assert(roadmap.CheckGraphLinkage());
|
||||
#ifdef ENABLE_PARALLEL_ROADMAP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (size_t current_node_index = 0; current_node_index < roadmap.GetNodesImmutable().size(); current_node_index++)
|
||||
{
|
||||
arc_dijkstras::GraphNode<T, Allocator>& current_node = roadmap.GetNodeMutable(current_node_index);
|
||||
std::vector<arc_dijkstras::GraphEdge>& current_node_out_edges = current_node.GetOutEdgesMutable();
|
||||
for (size_t out_edge_idx = 0; out_edge_idx < current_node_out_edges.size(); out_edge_idx++)
|
||||
{
|
||||
arc_dijkstras::GraphEdge& current_out_edge = current_node_out_edges[out_edge_idx];
|
||||
const int64_t other_node_idx = current_out_edge.GetToIndex();
|
||||
arc_dijkstras::GraphNode<T, Allocator>& other_node = roadmap.GetNodeMutable(other_node_idx);
|
||||
std::vector<arc_dijkstras::GraphEdge>& other_node_in_edges = other_node.GetInEdgesMutable();
|
||||
// If the edge is not valid, set the weight to infinity, otherwise use the distance function
|
||||
double updated_weight = std::numeric_limits<double>::infinity();
|
||||
if (edge_validity_check_fn(current_node.GetValueImmutable(), other_node.GetValueImmutable()))
|
||||
{
|
||||
updated_weight = distance_fn(current_node.GetValueImmutable(), other_node.GetValueImmutable());
|
||||
}
|
||||
// Update our out edge
|
||||
current_out_edge.SetWeight(updated_weight);
|
||||
// Update the other node's in edges
|
||||
for (size_t in_edge_idx = 0; in_edge_idx < other_node_in_edges.size(); in_edge_idx++)
|
||||
{
|
||||
arc_dijkstras::GraphEdge& other_in_edge = other_node_in_edges[in_edge_idx];
|
||||
if (other_in_edge.GetFromIndex() == current_node_index)
|
||||
{
|
||||
other_in_edge.SetWeight(updated_weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathAndAddNodesMultiStartSingleGoal(
|
||||
const std::vector<T, Allocator>& starts,
|
||||
const T& goal,
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
// Add the multiple start nodes to the roadmap
|
||||
std::vector<int64_t> start_node_indices(starts.size());
|
||||
for (size_t start_idx = 0; start_idx < starts.size(); start_idx++)
|
||||
{
|
||||
const T& start = starts[start_idx];
|
||||
start_node_indices[start_idx] = AddNodeToRoadmap(start, NEW_STATE_TO_ROADMAP, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
}
|
||||
// Add the goal node to the roadmap
|
||||
const int64_t goal_node_index = AddNodeToRoadmap(goal, ROADMAP_TO_NEW_STATE, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Call Dijkstra's
|
||||
const auto dijkstras_solution = arc_dijkstras::SimpleDijkstrasAlgorithm<T, Allocator>::PerformDijkstrasAlgorithm(roadmap, goal_node_index);
|
||||
// Identify the lowest-distance starting state
|
||||
const std::pair<std::vector<int64_t>, std::vector<double>>& solution_map_distances = dijkstras_solution.second;
|
||||
double best_start_node_distance = std::numeric_limits<double>::infinity();
|
||||
int64_t best_start_node_index = -1;
|
||||
for (size_t start_idx = 0; start_idx < starts.size(); start_idx++)
|
||||
{
|
||||
const int64_t start_node_index = start_node_indices[start_idx];
|
||||
const double start_node_distance = solution_map_distances.second[start_node_index];
|
||||
if (start_node_distance < best_start_node_distance)
|
||||
{
|
||||
best_start_node_distance = start_node_distance;
|
||||
best_start_node_index = start_node_index;
|
||||
}
|
||||
}
|
||||
const int64_t start_node_index = best_start_node_index;
|
||||
const double start_node_distance = best_start_node_distance;
|
||||
// Extract solution path
|
||||
if (std::isinf(start_node_distance))
|
||||
{
|
||||
return std::make_pair(std::vector<T, Allocator>(), std::numeric_limits<double>::infinity());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<int64_t> solution_path_indices;
|
||||
solution_path_indices.push_back(start_node_index);
|
||||
int64_t previous_index = solution_map_distances.first[start_node_index];
|
||||
while (previous_index >= 0)
|
||||
{
|
||||
const int64_t current_index = previous_index;
|
||||
solution_path_indices.push_back(current_index);
|
||||
if (current_index == goal_node_index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_index = solution_map_distances.first[current_index];
|
||||
}
|
||||
}
|
||||
const std::vector<T, Allocator> solution_path = ExtractSolutionPath(roadmap, solution_path_indices);
|
||||
return std::make_pair(solution_path, start_node_distance);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathAndAddNodesSingleStartSingleGoal(
|
||||
const T& start,
|
||||
const T& goal,
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true,
|
||||
const bool limit_astar_pqueue_duplicates = true)
|
||||
{
|
||||
// Add the start node to the roadmap
|
||||
const int64_t start_node_index = AddNodeToRoadmap(start, NEW_STATE_TO_ROADMAP, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Add the goal node to the roadmap
|
||||
const int64_t goal_node_index = AddNodeToRoadmap(goal, ROADMAP_TO_NEW_STATE, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Call graph A*
|
||||
const std::pair<std::vector<int64_t>, double> astar_result = arc_dijkstras::SimpleGraphAstar<T, Allocator>::PerformAstar(
|
||||
roadmap, start_node_index, goal_node_index, distance_fn, limit_astar_pqueue_duplicates);
|
||||
// Convert the solution path from A* provided as indices into real states
|
||||
const std::vector<int64_t>& solution_path_indices = astar_result.first;
|
||||
std::vector<T, Allocator> solution_path;
|
||||
solution_path.reserve(astar_result.first.size());
|
||||
for (size_t idx = 0; idx < solution_path_indices.size(); idx++)
|
||||
{
|
||||
const int64_t path_index = solution_path_indices[idx];
|
||||
solution_path.push_back(roadmap.GetNodeImmutable(path_index).GetValueImmutable());
|
||||
}
|
||||
solution_path.shrink_to_fit();
|
||||
return std::make_pair(solution_path, astar_result.second);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> LazyQueryPathAndAddNodesSingleStartSingleGoal(
|
||||
const T& start,
|
||||
const T& goal,
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K, const bool distance_is_symmetric=true,
|
||||
const bool limit_astar_pqueue_duplicates = true)
|
||||
{
|
||||
// Add the start node to the roadmap
|
||||
const int64_t start_node_index = AddNodeToRoadmap(start, NEW_STATE_TO_ROADMAP, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Add the goal node to the roadmap
|
||||
const int64_t goal_node_index = AddNodeToRoadmap(goal, ROADMAP_TO_NEW_STATE, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Call graph A*
|
||||
const std::pair<std::vector<int64_t>, double> astar_result = arc_dijkstras::SimpleGraphAstar<T, Allocator>::PerformLazyAstar(
|
||||
roadmap, start_node_index, goal_node_index, edge_validity_check_fn, distance_fn, distance_fn, limit_astar_pqueue_duplicates);
|
||||
// Convert the solution path from A* provided as indices into real states
|
||||
const std::vector<T, Allocator> solution_path = ExtractSolutionPath(roadmap, astar_result.first);
|
||||
return std::make_pair(solution_path, astar_result.second);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>, typename Generator = std::mt19937_64>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathAndAddNodesSingleStartSingleGoalRandomWalk(
|
||||
const T& start,
|
||||
const T& goal,
|
||||
Generator& generator,
|
||||
arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
// Add the start node to the roadmap
|
||||
const int64_t start_node_index = AddNodeToRoadmap(start, NEW_STATE_TO_ROADMAP, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Add the goal node to the roadmap
|
||||
const int64_t goal_node_index = AddNodeToRoadmap(goal, ROADMAP_TO_NEW_STATE, roadmap, distance_fn, edge_validity_check_fn, K, distance_is_symmetric);
|
||||
// Call the random walk algorithm
|
||||
const auto random_walk_result = arc_dijkstras::GraphRandomWalk<T, Allocator>::PerformRandomWalk(roadmap, start_node_index, goal_node_index, generator);
|
||||
// Convert the result into a path and return it
|
||||
const auto solution_path = ExtractSolutionPath(roadmap, random_walk_result);
|
||||
const auto distance = EigenHelpers::CalculateTotalDistance(solution_path, distance_fn);
|
||||
return std::make_pair(solution_path, distance);
|
||||
}
|
||||
|
||||
// TODO - figure out a better way to balance parallelism between KNN queries inside path calls and multiple calls to Dijkstras
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathMultiStartMultiGoal(
|
||||
const std::vector<T, Allocator>& starts,
|
||||
const std::vector<T, Allocator>& goals,
|
||||
const arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
std::vector<std::pair<std::vector<T, Allocator>, double>> possible_solutions(goals.size());
|
||||
for (size_t goal_idx = 0; goal_idx < goals.size(); goal_idx++)
|
||||
{
|
||||
possible_solutions[goal_idx] = QueryPathMultiStartSingleGoal(starts, goals[goal_idx], roadmap, edge_validity_check_fn, distance_fn, K, distance_is_symmetric);
|
||||
}
|
||||
const double best_solution_distance = std::numeric_limits<double>::infinity();
|
||||
const int64_t best_solution_index = -1;
|
||||
for (size_t goal_idx = 0; goal_idx < goals.size(); goal_idx++)
|
||||
{
|
||||
const double solution_distance = possible_solutions[goal_idx].second;
|
||||
if (solution_distance < best_solution_distance)
|
||||
{
|
||||
best_solution_distance = solution_distance;
|
||||
best_solution_index = goal_idx;
|
||||
}
|
||||
}
|
||||
if ((best_solution_index >= 0) && (best_solution_distance < std::numeric_limits<double>::infinity()))
|
||||
{
|
||||
return possible_solutions[best_solution_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair(std::vector<T, Allocator>(), std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathMultiStartSingleGoal(
|
||||
const std::vector<T, Allocator>& starts,
|
||||
const T& goal,
|
||||
const arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
arc_dijkstras::Graph<T, Allocator> working_copy = roadmap;
|
||||
return QueryPathAndAddNodesMultiStartSingleGoal(starts, goal, working_copy, edge_validity_check_fn, distance_fn, K, distance_is_symmetric);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> QueryPathSingleStartSingleGoal(
|
||||
const T& start,
|
||||
const T& goal,
|
||||
const arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
arc_dijkstras::Graph<T, Allocator> working_copy = roadmap;
|
||||
return QueryPathAndAddNodesSingleStartSingleGoal(start, goal, working_copy, edge_validity_check_fn, distance_fn, K, distance_is_symmetric);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, double> LazyQueryPathSingleStartSingleGoal(
|
||||
const T& start, const T& goal, const arc_dijkstras::Graph<T, Allocator>& roadmap,
|
||||
const std::function<bool(const T&, const T&)>& edge_validity_check_fn,
|
||||
const std::function<double(const T&, const T&)>& distance_fn,
|
||||
const size_t K,
|
||||
const bool distance_is_symmetric = true)
|
||||
{
|
||||
arc_dijkstras::Graph<T, Allocator> working_copy = roadmap;
|
||||
return LazyQueryPathAndAddNodesSingleStartSingleGoal(start, goal, working_copy, edge_validity_check_fn, distance_fn, K, distance_is_symmetric);
|
||||
}
|
||||
|
||||
// TODO update to provide lazy and non-lazy variants of single start/single goal
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SIMPLE_PRM_PLANNER
|
||||
887
flightlib/third_party/arc_utilities/include/arc_utilities/simple_rrt_planner.hpp
vendored
Normal file
887
flightlib/third_party/arc_utilities/include/arc_utilities/simple_rrt_planner.hpp
vendored
Normal file
@@ -0,0 +1,887 @@
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <memory>
|
||||
#include <Eigen/Dense>
|
||||
#include <arc_utilities/serialization.hpp>
|
||||
|
||||
#ifndef SIMPLE_RRT_PLANNER_HPP
|
||||
#define SIMPLE_RRT_PLANNER_HPP
|
||||
|
||||
namespace simple_rrt_planner
|
||||
{
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
class SimpleRRTPlannerState
|
||||
{
|
||||
protected:
|
||||
|
||||
T value_;
|
||||
std::vector<int64_t> child_indices_;
|
||||
int64_t parent_index_;
|
||||
bool initialized_;
|
||||
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
static uint64_t Serialize(const SimpleRRTPlannerState<T, Allocator>& state, std::vector<uint8_t>& buffer, const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
return state.SerializeSelf(buffer, value_serializer);
|
||||
}
|
||||
|
||||
static std::pair<SimpleRRTPlannerState<T, Allocator>, uint64_t> Deserialize(const std::vector<uint8_t>& buffer, const uint64_t current, const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
SimpleRRTPlannerState<T, Allocator> temp_state;
|
||||
const uint64_t bytes_read = temp_state.DeserializeSelf(buffer, current, value_deserializer);
|
||||
return std::make_pair(temp_state, bytes_read);
|
||||
}
|
||||
|
||||
SimpleRRTPlannerState()
|
||||
: parent_index_(-1)
|
||||
, initialized_(false)
|
||||
{
|
||||
child_indices_.clear();
|
||||
}
|
||||
|
||||
SimpleRRTPlannerState(const T& value, const int64_t parent_index, const std::vector<int64_t>& child_indices)
|
||||
: value_(value)
|
||||
, child_indices_(child_indices)
|
||||
, parent_index_(parent_index)
|
||||
, initialized_(true)
|
||||
{}
|
||||
|
||||
SimpleRRTPlannerState(const T& value, const int64_t parent_index)
|
||||
: value_(value)
|
||||
, parent_index_(parent_index)
|
||||
, initialized_(true)
|
||||
{
|
||||
child_indices_.clear();
|
||||
}
|
||||
|
||||
SimpleRRTPlannerState(const T& value)
|
||||
: value_(value)
|
||||
, parent_index_(-1)
|
||||
, initialized_(true)
|
||||
{
|
||||
child_indices_.clear();
|
||||
}
|
||||
|
||||
uint64_t SerializeSelf(std::vector<uint8_t>& buffer, const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer) const
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// Serialize the initialized
|
||||
arc_utilities::SerializeFixedSizePOD<uint8_t>((uint8_t)initialized_, buffer);
|
||||
// Serialize the parent index
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(parent_index_, buffer);
|
||||
// Serialize the child indices
|
||||
arc_utilities::SerializeVector<int64_t>(child_indices_, buffer, arc_utilities::SerializeFixedSizePOD<int64_t>);
|
||||
// Serialize the value
|
||||
value_serializer(value_, buffer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint64_t DeserializeSelf(const std::vector<uint8_t>& buffer, const uint64_t current, const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
uint64_t current_position = current;
|
||||
// Deserialize the initialized
|
||||
const std::pair<uint8_t, uint64_t> initialized_deserialized = arc_utilities::DeserializeFixedSizePOD<uint8_t>(buffer, current_position);
|
||||
initialized_ = (bool)initialized_deserialized.first;
|
||||
current_position += initialized_deserialized.second;
|
||||
// Deserialize the parent index
|
||||
const std::pair<int64_t, uint64_t> parent_index_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
parent_index_ = parent_index_deserialized.first;
|
||||
current_position += parent_index_deserialized.second;
|
||||
// Deserialize the child indices
|
||||
const std::pair<std::vector<int64_t>, uint64_t> child_indices_deserialized = arc_utilities::DeserializeVector<int64_t>(buffer, current_position, arc_utilities::DeserializeFixedSizePOD<int64_t>);
|
||||
child_indices_ = child_indices_deserialized.first;
|
||||
current_position += child_indices_deserialized.second;
|
||||
// Deserialize the value
|
||||
const std::pair<T, uint64_t> value_deserialized = value_deserializer(buffer, current_position);
|
||||
value_ = value_deserialized.first;
|
||||
current_position += value_deserialized.second;
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
const T& GetValueImmutable() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
T& GetValueMutable()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
int64_t GetParentIndex() const
|
||||
{
|
||||
return parent_index_;
|
||||
}
|
||||
|
||||
void SetParentIndex(const int64_t parent_index)
|
||||
{
|
||||
parent_index_ = parent_index;
|
||||
}
|
||||
|
||||
const std::vector<int64_t>& GetChildIndices() const
|
||||
{
|
||||
return child_indices_;
|
||||
}
|
||||
|
||||
void ClearChildIndicies()
|
||||
{
|
||||
child_indices_.clear();
|
||||
}
|
||||
|
||||
void AddChildIndex(const int64_t child_index)
|
||||
{
|
||||
for (size_t idx = 0; idx < child_indices_.size(); idx++)
|
||||
{
|
||||
if (child_indices_[idx] == child_index)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
child_indices_.push_back(child_index);
|
||||
}
|
||||
|
||||
void RemoveChildIndex(const int64_t child_index)
|
||||
{
|
||||
std::vector<int64_t> new_child_indices;
|
||||
for (size_t idx = 0; idx < child_indices_.size(); idx++)
|
||||
{
|
||||
if (child_indices_[idx] != child_index)
|
||||
{
|
||||
new_child_indices.push_back(child_indices_[idx]);
|
||||
}
|
||||
}
|
||||
child_indices_ = new_child_indices;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Allocator = std::allocator<T>>
|
||||
class SimpleRRTPlannerPointerState
|
||||
{
|
||||
protected:
|
||||
|
||||
T value_;
|
||||
std::shared_ptr<const SimpleRRTPlannerPointerState<T, Allocator>> parent_;
|
||||
bool initialized_;
|
||||
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
SimpleRRTPlannerPointerState()
|
||||
: parent_(nullptr)
|
||||
, initialized_(false)
|
||||
{}
|
||||
|
||||
SimpleRRTPlannerPointerState(const T& value, const std::shared_ptr<const SimpleRRTPlannerPointerState<T, Allocator>>& parent)
|
||||
: value_(value)
|
||||
, parent_(parent)
|
||||
, initialized_(true)
|
||||
{}
|
||||
|
||||
SimpleRRTPlannerPointerState(const T& value)
|
||||
: value_(value)
|
||||
, parent_(std::shared_ptr<const SimpleRRTPlannerPointerState<T, Allocator>>())
|
||||
, initialized_(true)
|
||||
{}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
const T& GetValueImmutable() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
T& GetValueMutable()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<const SimpleRRTPlannerPointerState<T, Allocator>>& GetParent() const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
void SetParent(const std::shared_ptr<const SimpleRRTPlannerPointerState<T, Allocator>>& parent)
|
||||
{
|
||||
parent_(parent);
|
||||
}
|
||||
};
|
||||
|
||||
class SimpleHybridRRTPlanner
|
||||
{
|
||||
private:
|
||||
|
||||
SimpleHybridRRTPlanner() {}
|
||||
|
||||
public:
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* goal - target configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of the goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* goal_bias - in (0, 1), selects the probability that the new sampled state is the goal state
|
||||
* time_limit - limit, in seconds, for the runtime of the planner
|
||||
* rng - a random number generator matching the interface of the generators provided by std::random
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename RNG, typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, std::map<std::string, double>> Plan(
|
||||
const T& start,
|
||||
const T& goal,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&,const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<T(void)>& state_sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const double goal_bias,
|
||||
const std::chrono::duration<double>& time_limit,
|
||||
RNG& rng)
|
||||
{
|
||||
std::uniform_real_distribution<double> goal_bias_distribution(0.0, 1.0);
|
||||
const std::function<T(void)> sampling_function = [&](void) { return ((goal_bias_distribution(rng) > goal_bias) ? state_sampling_fn() : goal); };
|
||||
return Plan(start, nearest_neighbor_fn, goal_reached_fn, sampling_function, forward_propagation_fn, time_limit);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* goal_sampling_fn - returns a goal state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* goal_bias - in (0, 1), selects the probability that the new sampled state is a goal state
|
||||
* time_limit - limit, in seconds, for the runtime of the planner
|
||||
* rng - a random number generator matching the interface of the generators provided by std::random
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename RNG, typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, std::map<std::string, double>> Plan(
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<T(void)>& state_sampling_fn,
|
||||
const std::function<T(void)>& goal_sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const double goal_bias,
|
||||
const std::chrono::duration<double>& time_limit,
|
||||
RNG& rng)
|
||||
{
|
||||
std::uniform_real_distribution<double> goal_bias_distribution(0.0, 1.0);
|
||||
const std::function<T(void)> sampling_function = [&](void) { return ((goal_bias_distribution(rng) > goal_bias) ? state_sampling_fn() : goal_sampling_fn()); };
|
||||
return Plan(start, nearest_neighbor_fn, goal_reached_fn, sampling_function, forward_propagation_fn, time_limit);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* time_limit - limit, in seconds, for the runtime of the planner
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, std::map<std::string, double>> Plan(
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::chrono::duration<double>& time_limit)
|
||||
{
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time = std::chrono::steady_clock::now();
|
||||
const std::function<bool(void)> termination_check_fn = [&](void) { return (((std::chrono::time_point<std::chrono::steady_clock>)std::chrono::steady_clock::now() - start_time) > time_limit); };
|
||||
return Plan(start, nearest_neighbor_fn, goal_reached_fn, sampling_fn, forward_propagation_fn, termination_check_fn);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, std::map<std::string, double>> Plan(
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Define a couple lambdas to let us use the generic multi-path planner as if it were a single-path planner
|
||||
bool solution_found = false;
|
||||
const std::function<bool(const T&)> real_goal_found_fn = [&](const T& state) { if (goal_reached_fn(state)) { solution_found = true; return true; } else {return false;} };
|
||||
const std::function<bool(void)> real_termination_check_fn = [&](void) { if (!solution_found) { return termination_check_fn(); } else {return true;} };
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)> dummy_goal_callback_fn = [](SimpleRRTPlannerState<T, Allocator>& state) {;};
|
||||
// Call the planner
|
||||
std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> planning_result = PlanMultiPath(start, nearest_neighbor_fn, real_goal_found_fn, dummy_goal_callback_fn, sampling_fn, forward_propagation_fn, real_termination_check_fn);
|
||||
// Put together the return
|
||||
std::vector<T, Allocator> planned_path;
|
||||
if (planning_result.first.size() > 0)
|
||||
{
|
||||
planned_path = planning_result.first[0];
|
||||
}
|
||||
return std::pair<std::vector<T, Allocator>, std::map<std::string, double>>(planned_path, planning_result.second);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* nodes - a mutable vector of planner states, used internally to store the planner tree.
|
||||
* This is provided to allow external use of the tree during and after planning.
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<T, Allocator>, std::map<std::string, double>> Plan(
|
||||
std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Define a couple lambdas to let us use the generic multi-path planner as if it were a single-path planner
|
||||
bool solution_found = false;
|
||||
const std::function<bool(const T&)> real_goal_found_fn = [&](const T& state) { if (goal_reached_fn(state)) { solution_found = true; return true; } else {return false;} };
|
||||
const std::function<bool(void)> real_termination_check_fn = [&](void) { if (!solution_found) { return termination_check_fn(); } else {return true;} };
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)> dummy_goal_callback_fn = [](SimpleRRTPlannerState<T, Allocator>& state) {;};
|
||||
// Call the planner
|
||||
std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> planning_result = PlanMultiPath(nodes, start, nearest_neighbor_fn, real_goal_found_fn, dummy_goal_callback_fn, sampling_fn, forward_propagation_fn, real_termination_check_fn);
|
||||
// Put together the return
|
||||
std::vector<T, Allocator> planned_path;
|
||||
if (planning_result.first.size() > 0)
|
||||
{
|
||||
planned_path = planning_result.first[0];
|
||||
}
|
||||
return std::pair<std::vector<T, Allocator>, std::map<std::string, double>>(planned_path, planning_result.second);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<paths, statistics>
|
||||
* paths - vector of vector of states corresponding to the planned path(s)
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> PlanMultiPath(
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)>& goal_reached_callback_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Keep track of states
|
||||
std::vector<SimpleRRTPlannerState<T, Allocator>> nodes;
|
||||
return PlanMultiPath(nodes, start, nearest_neighbor_fn, goal_reached_fn, goal_reached_callback_fn, sampling_fn, forward_propagation_fn, termination_check_fn);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* nodes - a mutable vector of planner states, used internally to store the planner tree.
|
||||
* This is provided to allow external use of the tree during and after planning.
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<paths, statistics>
|
||||
* paths - vector of vector of states corresponding to the planned path(s)
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> PlanMultiPath(
|
||||
std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const T& start,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)>& goal_reached_callback_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Clear the tree we've been given
|
||||
nodes.clear();
|
||||
// Add the start state
|
||||
SimpleRRTPlannerState<T, Allocator> start_state(start);
|
||||
nodes.push_back(start_state);
|
||||
// Call the planner
|
||||
return PlanMultiPath(nodes, nearest_neighbor_fn, goal_reached_fn, goal_reached_callback_fn, sampling_fn, forward_propagation_fn, termination_check_fn);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* nodes - a mutable vector of planner states, used internally to store the planner tree.
|
||||
* This is provided to allow external use of the tree during and after planning.
|
||||
* This contains either a SINGLE start state, or the tree resulting from previous planning.
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<paths, statistics>
|
||||
* paths - vector of vector of states corresponding to the planned path(s)
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> PlanMultiPath(
|
||||
std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)>& goal_reached_callback_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Make a dummy state added function
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&, SimpleRRTPlannerState<T, Allocator>&)> dummy_state_added_fn = [] (SimpleRRTPlannerState<T, Allocator>& parent, SimpleRRTPlannerState<T, Allocator>& new_child) { ; };
|
||||
// Call the planner
|
||||
return PlanMultiPath(nodes, nearest_neighbor_fn, dummy_state_added_fn, goal_reached_fn, goal_reached_callback_fn, sampling_fn, forward_propagation_fn, termination_check_fn);
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* nodes - a mutable vector of planner states, used internally to store the planner tree.
|
||||
* This is provided to allow external use of the tree during and after planning.
|
||||
* This contains either a SINGLE start state, or the tree resulting from previous planning.
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* state_added_fn - callback function that takes (parent, child) for each extension
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* termination_check_fn - returns if the planner should terminate (for example, if it has exceeded time/space limits)
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<paths, statistics>
|
||||
* paths - vector of vector of states corresponding to the planned path(s)
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>> PlanMultiPath(
|
||||
std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const std::function<int64_t(const std::vector<SimpleRRTPlannerState<T, Allocator>>&, const T&)>& nearest_neighbor_fn,
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&, SimpleRRTPlannerState<T, Allocator>&)>& state_added_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<void(SimpleRRTPlannerState<T, Allocator>&)>& goal_reached_callback_fn,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<std::vector<std::pair<T, int64_t>>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Make sure we've been given a start state
|
||||
assert(nodes.size() > 0);
|
||||
// Make sure the tree is properly linked
|
||||
assert(CheckTreeLinkage(nodes));
|
||||
// Keep track of statistics
|
||||
std::map<std::string, double> statistics;
|
||||
statistics["total_samples"] = 0.0;
|
||||
statistics["successful_samples"] = 0.0;
|
||||
statistics["failed_samples"] = 0.0;
|
||||
// Storage for the goal states we reach
|
||||
std::vector<int64_t> goal_state_indices;
|
||||
// Safety check before doing real work
|
||||
if (goal_reached_fn(nodes[0].GetValueImmutable()))
|
||||
{
|
||||
goal_state_indices.push_back(0);
|
||||
std::cerr << "Start state meets goal conditions, returning default path [start]" << std::endl;
|
||||
// Put together the results
|
||||
std::vector<std::vector<T>> planned_paths = ExtractSolutionPaths(nodes, goal_state_indices);
|
||||
statistics["planning_time"] = 0.0;
|
||||
statistics["total_states"] = nodes.size();
|
||||
statistics["solutions"] = (double)planned_paths.size();
|
||||
return std::pair<std::vector<std::vector<T>>, std::map<std::string, double>>(planned_paths, statistics);
|
||||
}
|
||||
// Update the start time
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time = std::chrono::steady_clock::now();
|
||||
// Plan
|
||||
while (!termination_check_fn())
|
||||
{
|
||||
// Sample a random goal
|
||||
T random_target = sampling_fn();
|
||||
// Get the nearest neighbor
|
||||
int64_t nearest_neighbor_index = nearest_neighbor_fn(nodes, random_target);
|
||||
assert((nearest_neighbor_index >= 0) && (nearest_neighbor_index < nodes.size()));
|
||||
const T& nearest_neighbor = nodes.at(nearest_neighbor_index).GetValueImmutable();
|
||||
// Forward propagate towards the goal
|
||||
std::vector<std::pair<T, int64_t>> propagated = forward_propagation_fn(nearest_neighbor, random_target);
|
||||
if (!propagated.empty())
|
||||
{
|
||||
statistics["total_samples"] += 1.0;
|
||||
statistics["successful_samples"] += 1.0;
|
||||
for (size_t idx = 0; idx < propagated.size(); idx++)
|
||||
{
|
||||
const std::pair<T, int64_t>& current_propagation = propagated[idx];
|
||||
// Determine the parent index of the new state
|
||||
// This process deserves some explanation
|
||||
// The "current relative parent index" is the index of the parent, relative to the list of propagated nodes.
|
||||
// A negative value means the nearest neighbor in the tree, zero means the first propagated node, and so on.
|
||||
// NOTE - the relative parent index *must* be lower than the index in the list of prograted nodes
|
||||
// i.e. the first node must have a negative value, and so on.
|
||||
const int64_t& current_relative_parent_index = current_propagation.second;
|
||||
int64_t node_parent_index = nearest_neighbor_index;
|
||||
if (current_relative_parent_index >= 0)
|
||||
{
|
||||
const int64_t current_relative_index = (int64_t)idx;
|
||||
assert(current_relative_parent_index < current_relative_index);
|
||||
const int64_t current_relative_offset = current_relative_parent_index - current_relative_index;
|
||||
assert(current_relative_offset < 0);
|
||||
assert(current_relative_offset >= -(int64_t)propagated.size());
|
||||
const int64_t current_nodes_size = (int64_t)nodes.size();
|
||||
node_parent_index = current_nodes_size + current_relative_offset; // Offset is negative!
|
||||
}
|
||||
else
|
||||
{
|
||||
node_parent_index = nearest_neighbor_index; // Negative relative parent index means our parent index is the nearest neighbor index
|
||||
}
|
||||
// Build the new state
|
||||
const T& current_propagated = current_propagation.first;
|
||||
SimpleRRTPlannerState<T, Allocator> new_state(current_propagated, node_parent_index);
|
||||
// Add the state to the tree
|
||||
nodes.push_back(new_state);
|
||||
int64_t new_node_index = (int64_t)nodes.size() - 1;
|
||||
nodes[node_parent_index].AddChildIndex(new_node_index);
|
||||
// Call the state added callback
|
||||
state_added_fn(nodes[node_parent_index], nodes[new_node_index]);
|
||||
// Check if we've reached the goal
|
||||
if (goal_reached_fn(nodes[new_node_index].GetValueImmutable()))
|
||||
{
|
||||
goal_state_indices.push_back(new_node_index);
|
||||
goal_reached_callback_fn(nodes[new_node_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics["total_samples"] += 1.0;
|
||||
statistics["failed_samples"] += 1.0;
|
||||
}
|
||||
}
|
||||
// Put together the results
|
||||
// Make sure the tree is properly linked
|
||||
assert(CheckTreeLinkage(nodes));
|
||||
std::vector<std::vector<T, Allocator>> planned_paths = ExtractSolutionPaths(nodes, goal_state_indices);
|
||||
std::chrono::time_point<std::chrono::steady_clock> cur_time = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> planning_time(cur_time - start_time);
|
||||
statistics["planning_time"] = planning_time.count();
|
||||
statistics["total_states"] = nodes.size();
|
||||
statistics["solutions"] = (double)planned_paths.size();
|
||||
return std::pair<std::vector<std::vector<T, Allocator>>, std::map<std::string, double>>(planned_paths, statistics);
|
||||
}
|
||||
|
||||
/* Checks the planner tree to make sure the parent-child linkages are correct
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static bool CheckTreeLinkage(const std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes)
|
||||
{
|
||||
// Step through each state in the tree. Make sure that the linkage to the parent and child states are correct
|
||||
for (size_t current_index = 0; current_index < nodes.size(); current_index++)
|
||||
{
|
||||
// For every state, make sure all the parent<->child linkages are valid
|
||||
const SimpleRRTPlannerState<T, Allocator>& current_state = nodes[current_index];
|
||||
if (!current_state.IsInitialized())
|
||||
{
|
||||
std::cerr << "Tree contains uninitialized node(s) " << current_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
// Check the linkage to the parent state
|
||||
const int64_t parent_index = current_state.GetParentIndex();
|
||||
if ((parent_index >= 0) && (parent_index < (int64_t)nodes.size()))
|
||||
{
|
||||
if (parent_index != (int64_t)current_index)
|
||||
{
|
||||
const SimpleRRTPlannerState<T, Allocator>& parent_state = nodes[parent_index];
|
||||
if (!parent_state.IsInitialized())
|
||||
{
|
||||
std::cerr << "Tree contains uninitialized node(s) " << parent_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
// Make sure the corresponding parent contains the current node in the list of child indices
|
||||
const std::vector<int64_t>& parent_child_indices = parent_state.GetChildIndices();
|
||||
auto index_found = std::find(parent_child_indices.begin(), parent_child_indices.end(), (int64_t)current_index);
|
||||
if (index_found == parent_child_indices.end())
|
||||
{
|
||||
std::cerr << "Parent state " << parent_index << " does not contain child index for current node " << current_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid parent index " << parent_index << " for state " << current_index << " [Indices can't be the same]" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (parent_index < -1)
|
||||
{
|
||||
std::cerr << "Invalid parent index " << parent_index << " for state " << current_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
// Check the linkage to the child states
|
||||
const std::vector<int64_t>& current_child_indices = current_state.GetChildIndices();
|
||||
for (size_t idx = 0; idx < current_child_indices.size(); idx++)
|
||||
{
|
||||
// Get the current child index
|
||||
const int64_t current_child_index = current_child_indices[idx];
|
||||
if ((current_child_index > 0) && (current_child_index < (int64_t)nodes.size()))
|
||||
{
|
||||
if (current_child_index != (int64_t)current_index)
|
||||
{
|
||||
const SimpleRRTPlannerState<T, Allocator>& child_state = nodes[current_child_index];
|
||||
if (!child_state.IsInitialized())
|
||||
{
|
||||
std::cerr << "Tree contains uninitialized node(s) " << current_child_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
// Make sure the child node points to us as the parent index
|
||||
const int64_t child_parent_index = child_state.GetParentIndex();
|
||||
if (child_parent_index != (int64_t)current_index)
|
||||
{
|
||||
std::cerr << "Parent index " << child_parent_index << " for current child state " << current_child_index << " does not match index " << current_index << " for current node " << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid child index " << current_child_index << " for state " << current_index << " [Indices can't be the same]" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid child index " << current_child_index << " for state " << current_index << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Extracts all the solution paths corresponding to the provided goal states
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::vector<std::vector<T, Allocator>> ExtractSolutionPaths(
|
||||
const std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const std::vector<int64_t>& goal_state_indices)
|
||||
{
|
||||
std::vector<std::vector<T, Allocator>> solution_paths;
|
||||
for (size_t idx = 0; idx < goal_state_indices.size(); idx++)
|
||||
{
|
||||
std::vector<T, Allocator> solution_path = ExtractSolutionPath(nodes, goal_state_indices[idx]);
|
||||
solution_paths.push_back(solution_path);
|
||||
}
|
||||
return solution_paths;
|
||||
}
|
||||
|
||||
/* Extracts a single solution path corresponding to the provided goal state
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::vector<T, Allocator> ExtractSolutionPath(
|
||||
const std::vector<SimpleRRTPlannerState<T, Allocator>>& nodes,
|
||||
const int64_t goal_state_index)
|
||||
{
|
||||
std::vector<T, Allocator> solution_path;
|
||||
const SimpleRRTPlannerState<T, Allocator>& goal_state = nodes[goal_state_index];
|
||||
solution_path.push_back(goal_state.GetValueImmutable());
|
||||
int64_t parent_index = goal_state.GetParentIndex();
|
||||
while (parent_index >= 0)
|
||||
{
|
||||
assert(parent_index < nodes.size());
|
||||
const SimpleRRTPlannerState<T, Allocator>& parent_state = nodes[parent_index];
|
||||
const T& parent = parent_state.GetValueImmutable();
|
||||
solution_path.push_back(parent);
|
||||
parent_index = parent_state.GetParentIndex();
|
||||
}
|
||||
// Put it in the right order
|
||||
std::reverse(solution_path.begin(), solution_path.end());
|
||||
return solution_path;
|
||||
}
|
||||
|
||||
/* Template-based single-tree RRT planner
|
||||
*
|
||||
* Template type T is your state type (i.e. a configuration)
|
||||
*
|
||||
* Arguments:
|
||||
* start - starting configuration
|
||||
* nearest_neighbor_fn - given all nodes explored so far, and a new state, return the index of the "closest" node
|
||||
* goal_reached_fn - return if a given state meets the goal conditions (for example, within a radius of a goal state)
|
||||
* state_sampling_fn - returns a new state (randomly- or deterministically-sampled)
|
||||
* forward_propagation_fn - given the nearest neighbor and a new target state, returns the states that would grow the tree towards the target
|
||||
* time_limit - limit, in seconds, for the runtime of the planner
|
||||
*
|
||||
* Returns:
|
||||
* std::pair<path, statistics>
|
||||
* path - vector of states corresponding to the planned path
|
||||
* statistics - map of string keys/double values of planner statistics (i.e. run time, #states explored, #states in solution
|
||||
*/
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
static std::pair<std::vector<std::vector<T>>, std::map<std::string, double>> PlanMultiPath(
|
||||
const T& start,
|
||||
const std::function<void(const std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>>&)>& register_nearest_neighbors_fn,
|
||||
const std::function<const std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>>&(const T&)>& get_nearest_neighbor_fn,
|
||||
const std::function<std::vector<std::vector<T>>(void)>& extract_solution_paths,
|
||||
const std::function<T(void)>& sampling_fn,
|
||||
const std::function<bool(const T&)>& goal_reached_fn,
|
||||
const std::function<void(const std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>>&)>& register_goal_state_fn,
|
||||
const std::function<std::vector<T>(const T&, const T&)>& forward_propagation_fn,
|
||||
const std::function<bool(void)>& termination_check_fn)
|
||||
{
|
||||
// Keep track of statistics
|
||||
std::map<std::string, double> statistics;
|
||||
statistics["total_states"] = 0.0;
|
||||
statistics["total_samples"] = 0.0;
|
||||
statistics["successful_samples"] = 0.0;
|
||||
statistics["failed_samples"] = 0.0;
|
||||
// Add the start state
|
||||
SimpleRRTPlannerState<T, Allocator> start_state(start);
|
||||
register_nearest_neighbors_fn(start_state);
|
||||
// Update the start time
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time = std::chrono::steady_clock::now();
|
||||
// Plan
|
||||
while (!termination_check_fn())
|
||||
{
|
||||
// Sample a random goal
|
||||
T random_target = sampling_fn();
|
||||
// Get the nearest neighbor
|
||||
const std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>>& nearest_neighbor_ptr = get_nearest_neighbor_fn(random_target);
|
||||
assert(nearest_neighbor_ptr);
|
||||
const T& nearest_neighbor_value = nearest_neighbor_ptr->GetValueImmutable();
|
||||
// Forward propagate towards the goal
|
||||
std::vector<T> propagated = forward_propagation_fn(nearest_neighbor_value, random_target);
|
||||
if (!propagated.empty())
|
||||
{
|
||||
statistics["total_samples"] += 1.0;
|
||||
statistics["successful_samples"] += 1.0;
|
||||
std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>> parent_ptr(nearest_neighbor_ptr);
|
||||
for (size_t idx = 0; idx < propagated.size(); idx++)
|
||||
{
|
||||
statistics["total_states"] += 1.0;
|
||||
const T& current_propagated = propagated[idx];
|
||||
std::shared_ptr<SimpleRRTPlannerPointerState<T, Allocator>> new_state_ptr(new SimpleRRTPlannerPointerState<T, Allocator>(current_propagated, parent_ptr));
|
||||
// If we've reached a goal, register it specially
|
||||
if (goal_reached_fn(current_propagated))
|
||||
{
|
||||
register_goal_state_fn(new_state_ptr);
|
||||
break;
|
||||
}
|
||||
// Otherwise, simply register it as a nearest neighbor
|
||||
else
|
||||
{
|
||||
register_nearest_neighbors_fn(new_state_ptr);
|
||||
parent_ptr = new_state_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics["total_samples"] += 1.0;
|
||||
statistics["failed_samples"] += 1.0;
|
||||
}
|
||||
}
|
||||
// Put together the results
|
||||
std::chrono::time_point<std::chrono::steady_clock> cur_time = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> planning_time(cur_time - start_time);
|
||||
std::vector<std::vector<T>> planned_paths = extract_solution_paths();
|
||||
statistics["planning_time"] = planning_time.count();
|
||||
statistics["solutions"] = (double)planned_paths.size();
|
||||
return std::pair<std::vector<std::vector<T>>, std::map<std::string, double>>(planned_paths, statistics);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SIMPLE_RRT_PLANNER
|
||||
35
flightlib/third_party/arc_utilities/include/arc_utilities/timing.hpp
vendored
Normal file
35
flightlib/third_party/arc_utilities/include/arc_utilities/timing.hpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef ARC_UTILITIES_TIMING_HPP
|
||||
#define ARC_UTILITIES_TIMING_HPP
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace arc_utilities
|
||||
{
|
||||
enum StopwatchControl {RESET, READ};
|
||||
|
||||
class Stopwatch
|
||||
{
|
||||
public:
|
||||
Stopwatch()
|
||||
: start_time_(std::chrono::steady_clock::now())
|
||||
{}
|
||||
|
||||
double operator() (const StopwatchControl control = READ)
|
||||
{
|
||||
const auto end_time = std::chrono::steady_clock::now();
|
||||
if (control == RESET)
|
||||
{
|
||||
start_time_ = end_time;
|
||||
}
|
||||
|
||||
return std::chrono::duration<double>(end_time - start_time_).count();
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::steady_clock::time_point start_time_;
|
||||
};
|
||||
|
||||
double GlobalStopwatch(const StopwatchControl control = READ);
|
||||
}
|
||||
|
||||
#endif // ARC_UTILITIES_TIMING_HPP
|
||||
926
flightlib/third_party/arc_utilities/include/arc_utilities/voxel_grid.hpp
vendored
Normal file
926
flightlib/third_party/arc_utilities/include/arc_utilities/voxel_grid.hpp
vendored
Normal file
@@ -0,0 +1,926 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <Eigen/Geometry>
|
||||
#include <stdexcept>
|
||||
#include <arc_utilities/arc_helpers.hpp>
|
||||
#include <arc_utilities/serialization_eigen.hpp>
|
||||
#include <arc_utilities/eigen_helpers.hpp>
|
||||
|
||||
#ifndef VOXEL_GRID_HPP
|
||||
#define VOXEL_GRID_HPP
|
||||
|
||||
namespace VoxelGrid
|
||||
{
|
||||
struct GRID_INDEX
|
||||
{
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
int64_t z;
|
||||
|
||||
GRID_INDEX() : x(-1), y(-1), z(-1) {}
|
||||
|
||||
GRID_INDEX(const int64_t in_x, const int64_t in_y, const int64_t in_z) : x(in_x), y(in_y), z(in_z) {}
|
||||
|
||||
bool operator==(const GRID_INDEX& other) const
|
||||
{
|
||||
return (x == other.x && y == other.y && z == other.z);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Allocator=std::allocator<T>>
|
||||
class VoxelGrid
|
||||
{
|
||||
protected:
|
||||
|
||||
Eigen::Isometry3d origin_transform_;
|
||||
Eigen::Isometry3d inverse_origin_transform_;
|
||||
T default_value_;
|
||||
T oob_value_;
|
||||
std::vector<T, Allocator> data_;
|
||||
double cell_x_size_;
|
||||
double cell_y_size_;
|
||||
double cell_z_size_;
|
||||
double inv_cell_x_size_;
|
||||
double inv_cell_y_size_;
|
||||
double inv_cell_z_size_;
|
||||
double x_size_;
|
||||
double y_size_;
|
||||
double z_size_;
|
||||
int64_t stride1_;
|
||||
int64_t stride2_;
|
||||
int64_t num_x_cells_;
|
||||
int64_t num_y_cells_;
|
||||
int64_t num_z_cells_;
|
||||
bool initialized_;
|
||||
|
||||
inline int64_t GetDataIndex(const int64_t x_index, const int64_t y_index, const int64_t z_index) const
|
||||
{
|
||||
return (x_index * stride1_) + (y_index * stride2_) + z_index;
|
||||
}
|
||||
|
||||
inline void SetContents(const T& value)
|
||||
{
|
||||
data_.clear();
|
||||
data_.resize(num_x_cells_ * num_y_cells_ * num_z_cells_, value);
|
||||
}
|
||||
|
||||
inline void SafetyCheckSizes(const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size,const double y_size, const double z_size) const
|
||||
{
|
||||
if (cell_x_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_x_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_x_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must not be INF");
|
||||
}
|
||||
if (cell_y_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_y_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_y_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must not be INF");
|
||||
}
|
||||
if (cell_z_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_z_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_z_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must not be INF");
|
||||
}
|
||||
if (x_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("x_size must be positive and non-zero");
|
||||
}
|
||||
if (y_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("y_size must be positive and non-zero");
|
||||
}
|
||||
if (z_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("z_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(x_size))
|
||||
{
|
||||
throw std::invalid_argument("x_size must not be NaN");
|
||||
}
|
||||
if (std::isnan(y_size))
|
||||
{
|
||||
throw std::invalid_argument("y_size must not be NaN");
|
||||
}
|
||||
if (std::isnan(z_size))
|
||||
{
|
||||
throw std::invalid_argument("z_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(x_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("x_size must not be INF");
|
||||
}
|
||||
if (std::isinf(y_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("y_size must not be INF");
|
||||
}
|
||||
if (std::isinf(z_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("z_size must not be INF");
|
||||
}
|
||||
}
|
||||
|
||||
inline void SafetyCheckSizes(const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells,const int64_t num_y_cells, const int64_t num_z_cells) const
|
||||
{
|
||||
if (cell_x_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_x_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_x_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_x_size must not be INF");
|
||||
}
|
||||
if (cell_y_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_y_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_y_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_y_size must not be INF");
|
||||
}
|
||||
if (cell_z_size <= 0.0)
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must be positive and non-zero");
|
||||
}
|
||||
if (std::isnan(cell_z_size))
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must not be NaN");
|
||||
}
|
||||
if (std::isinf(cell_z_size) != 0)
|
||||
{
|
||||
throw std::invalid_argument("cell_z_size must not be INF");
|
||||
}
|
||||
if (num_x_cells <= 0)
|
||||
{
|
||||
throw std::invalid_argument("num_x_cells must be positive and non-zero");
|
||||
}
|
||||
if (num_y_cells <= 0)
|
||||
{
|
||||
throw std::invalid_argument("num_y_cells must be positive and non-zero");
|
||||
}
|
||||
if (num_z_cells <= 0)
|
||||
{
|
||||
throw std::invalid_argument("num_z_cells must be positive and non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
inline void CoreInitialize(const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
SafetyCheckSizes(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells);
|
||||
cell_x_size_ = fabs(cell_x_size);
|
||||
cell_y_size_ = fabs(cell_y_size);
|
||||
cell_z_size_ = fabs(cell_z_size);
|
||||
inv_cell_x_size_ = 1.0 / cell_x_size_;
|
||||
inv_cell_y_size_ = 1.0 / cell_y_size_;
|
||||
inv_cell_z_size_ = 1.0 / cell_z_size_;
|
||||
num_x_cells_ = num_x_cells;
|
||||
num_y_cells_ = num_y_cells;
|
||||
num_z_cells_ = num_z_cells;
|
||||
x_size_ = (double)num_x_cells_ * cell_x_size_;
|
||||
y_size_ = (double)num_y_cells_ * cell_y_size_;
|
||||
z_size_ = (double)num_z_cells_ * cell_z_size_;
|
||||
default_value_ = default_value;
|
||||
oob_value_ = oob_value;
|
||||
stride1_ = num_y_cells_ * num_z_cells_;
|
||||
stride2_ = num_z_cells_;
|
||||
SetContents(default_value_);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
inline static uint64_t Serialize(const VoxelGrid<T, Allocator>& grid, std::vector<uint8_t>& buffer, const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer)
|
||||
{
|
||||
return grid.SerializeSelf(buffer, value_serializer);
|
||||
}
|
||||
|
||||
inline static std::pair<VoxelGrid<T, Allocator>, uint64_t> Deserialize(const std::vector<uint8_t>& buffer, const uint64_t current, const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
VoxelGrid<T, Allocator> temp_grid;
|
||||
const uint64_t bytes_read = temp_grid.DeserializeSelf(buffer, current, value_deserializer);
|
||||
return std::make_pair(temp_grid, bytes_read);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_size, const double x_size, const double y_size, double const z_size, const T& default_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_size, cell_size, cell_size, x_size, y_size, z_size, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_size, const double x_size, const double y_size, const double z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_size, cell_size, cell_size, x_size, y_size, z_size, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, double const z_size, const T& default_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, const double z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_size, cell_size, cell_size, num_x_cells, num_y_cells, num_z_cells, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_size, cell_size, cell_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(origin_transform, cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_size, const double x_size, const double y_size, const double z_size, const T& default_value)
|
||||
{
|
||||
Initialize(cell_size, cell_size, cell_size, x_size, y_size, z_size, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_size, const double x_size, const double y_size, const double z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(cell_size, cell_size, cell_size, x_size, y_size, z_size, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, const double z_size, const T& default_value)
|
||||
{
|
||||
Initialize(cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, const double z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value)
|
||||
{
|
||||
Initialize(cell_size, cell_size, cell_size, num_x_cells, num_y_cells, num_z_cells, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(cell_size, cell_size, cell_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value)
|
||||
{
|
||||
Initialize(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, default_value);
|
||||
}
|
||||
|
||||
VoxelGrid(const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
Initialize(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
VoxelGrid()
|
||||
{
|
||||
origin_transform_ = Eigen::Isometry3d::Identity();
|
||||
inverse_origin_transform_ = origin_transform_.inverse();
|
||||
arc_helpers::RequireAlignment(origin_transform_, 16u);
|
||||
arc_helpers::RequireAlignment(inverse_origin_transform_, 16u);
|
||||
cell_x_size_ = 0.0;
|
||||
cell_y_size_ = 0.0;
|
||||
cell_z_size_ = 0.0;
|
||||
inv_cell_x_size_ = 0.0;
|
||||
inv_cell_y_size_ = 0.0;
|
||||
inv_cell_z_size_ = 0.0;
|
||||
x_size_ = 0.0;
|
||||
y_size_ = 0.0;
|
||||
z_size_ = 0.0;
|
||||
num_x_cells_ = 0;
|
||||
num_y_cells_ = 0;
|
||||
num_z_cells_ = 0;
|
||||
stride1_ = num_y_cells_ * num_z_cells_;
|
||||
stride2_ = num_z_cells_;
|
||||
data_.clear();
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
inline void Initialize(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, double const z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
SafetyCheckSizes(cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size);
|
||||
int64_t num_x_cells = (int64_t)(ceil(fabs(x_size) / fabs(cell_x_size)));
|
||||
int64_t num_y_cells = (int64_t)(ceil(fabs(y_size) / fabs(cell_y_size)));
|
||||
int64_t num_z_cells = (int64_t)(ceil(fabs(z_size) / fabs(cell_z_size)));
|
||||
Initialize(origin_transform, cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
inline void Initialize(const Eigen::Isometry3d& origin_transform, const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
SafetyCheckSizes(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells);
|
||||
CoreInitialize(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
origin_transform_ = origin_transform;
|
||||
inverse_origin_transform_ = origin_transform_.inverse();
|
||||
arc_helpers::RequireAlignment(origin_transform_, 16u);
|
||||
arc_helpers::RequireAlignment(inverse_origin_transform_, 16u);
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
inline void Initialize(const double cell_x_size, const double cell_y_size, const double cell_z_size, const double x_size, const double y_size, double const z_size, const T& default_value, const T& oob_value)
|
||||
{
|
||||
SafetyCheckSizes(cell_x_size, cell_y_size, cell_z_size, x_size, y_size, z_size);
|
||||
int64_t num_x_cells = (int64_t)(ceil(fabs(x_size) / fabs(cell_x_size)));
|
||||
int64_t num_y_cells = (int64_t)(ceil(fabs(y_size) / fabs(cell_y_size)));
|
||||
int64_t num_z_cells = (int64_t)(ceil(fabs(z_size) / fabs(cell_z_size)));
|
||||
Initialize(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
}
|
||||
|
||||
inline void Initialize(const double cell_x_size, const double cell_y_size, const double cell_z_size, const int64_t num_x_cells, const int64_t num_y_cells, const int64_t num_z_cells, const T& default_value, const T& oob_value)
|
||||
{
|
||||
SafetyCheckSizes(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells);
|
||||
CoreInitialize(cell_x_size, cell_y_size, cell_z_size, num_x_cells, num_y_cells, num_z_cells, default_value, oob_value);
|
||||
const Eigen::Translation3d origin_translation(-x_size_ * 0.5, -y_size_ * 0.5, -z_size_ * 0.5);
|
||||
const Eigen::Isometry3d origin_transform = origin_translation * Eigen::Quaterniond::Identity();
|
||||
origin_transform_ = origin_transform;
|
||||
inverse_origin_transform_ = origin_transform_.inverse();
|
||||
arc_helpers::RequireAlignment(origin_transform_, 16u);
|
||||
arc_helpers::RequireAlignment(inverse_origin_transform_, 16u);
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
inline uint64_t SerializeSelf(std::vector<uint8_t>& buffer, const std::function<uint64_t(const T&, std::vector<uint8_t>&)>& value_serializer) const
|
||||
{
|
||||
const uint64_t start_buffer_size = buffer.size();
|
||||
// Serialize the initialized
|
||||
arc_utilities::SerializeFixedSizePOD<uint8_t>((uint8_t)initialized_, buffer);
|
||||
// Serialize the transforms
|
||||
arc_utilities::SerializeEigenType<Eigen::Isometry3d>(origin_transform_, buffer);
|
||||
arc_utilities::SerializeEigenType<Eigen::Isometry3d>(inverse_origin_transform_, buffer);
|
||||
// Serialize the data
|
||||
arc_utilities::SerializeVector<T, Allocator>(data_, buffer, value_serializer);
|
||||
// Serialize the cell sizes
|
||||
arc_utilities::SerializeFixedSizePOD<double>(cell_x_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(cell_y_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(cell_z_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(inv_cell_x_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(inv_cell_y_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(inv_cell_z_size_, buffer);
|
||||
// Serialize the grid sizes
|
||||
arc_utilities::SerializeFixedSizePOD<double>(x_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(y_size_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<double>(z_size_, buffer);
|
||||
// Serialize the control/bounds values
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(stride1_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(stride2_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(num_x_cells_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(num_y_cells_, buffer);
|
||||
arc_utilities::SerializeFixedSizePOD<int64_t>(num_z_cells_, buffer);
|
||||
// Serialize the default value
|
||||
value_serializer(default_value_, buffer);
|
||||
// Serialize the OOB value
|
||||
value_serializer(oob_value_, buffer);
|
||||
// Figure out how many bytes were written
|
||||
const uint64_t end_buffer_size = buffer.size();
|
||||
const uint64_t bytes_written = end_buffer_size - start_buffer_size;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
inline uint64_t DeserializeSelf(const std::vector<uint8_t>& buffer, const uint64_t current, const std::function<std::pair<T, uint64_t>(const std::vector<uint8_t>&, const uint64_t)>& value_deserializer)
|
||||
{
|
||||
uint64_t current_position = current;
|
||||
// Deserialize the initialized
|
||||
const std::pair<uint8_t, uint64_t> initialized_deserialized = arc_utilities::DeserializeFixedSizePOD<uint8_t>(buffer, current_position);
|
||||
initialized_ = (bool)initialized_deserialized.first;
|
||||
current_position += initialized_deserialized.second;
|
||||
// Deserialize the transforms
|
||||
const std::pair<Eigen::Isometry3d, uint64_t> origin_transform_deserialized = arc_utilities::DeserializeEigenType<Eigen::Isometry3d>(buffer, current_position);
|
||||
origin_transform_ = origin_transform_deserialized.first;
|
||||
current_position += origin_transform_deserialized.second;
|
||||
const std::pair<Eigen::Isometry3d, uint64_t> inverse_origin_transform_deserialized = arc_utilities::DeserializeEigenType<Eigen::Isometry3d>(buffer, current_position);
|
||||
inverse_origin_transform_ = inverse_origin_transform_deserialized.first;
|
||||
current_position += inverse_origin_transform_deserialized.second;
|
||||
// Deserialize the data
|
||||
const std::pair<std::vector<T, Allocator>, uint64_t> data_deserialized = arc_utilities::DeserializeVector<T, Allocator>(buffer, current_position, value_deserializer);
|
||||
data_ = data_deserialized.first;
|
||||
current_position += data_deserialized.second;
|
||||
// Deserialize the cell sizes
|
||||
const std::pair<double, uint64_t> cell_x_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
cell_x_size_ = cell_x_size_deserialized.first;
|
||||
current_position += cell_x_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> cell_y_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
cell_y_size_ = cell_y_size_deserialized.first;
|
||||
current_position += cell_y_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> cell_z_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
cell_z_size_ = cell_z_size_deserialized.first;
|
||||
current_position += cell_z_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> inv_cell_x_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
inv_cell_x_size_ = inv_cell_x_size_deserialized.first;
|
||||
current_position += inv_cell_x_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> inv_cell_y_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
inv_cell_y_size_ = inv_cell_y_size_deserialized.first;
|
||||
current_position += inv_cell_y_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> inv_cell_z_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
inv_cell_z_size_ = inv_cell_z_size_deserialized.first;
|
||||
current_position += inv_cell_z_size_deserialized.second;
|
||||
// Deserialize the grid sizes
|
||||
const std::pair<double, uint64_t> x_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
x_size_ = x_size_deserialized.first;
|
||||
current_position += x_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> y_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
y_size_ = y_size_deserialized.first;
|
||||
current_position += y_size_deserialized.second;
|
||||
const std::pair<double, uint64_t> z_size_deserialized = arc_utilities::DeserializeFixedSizePOD<double>(buffer, current_position);
|
||||
z_size_ = z_size_deserialized.first;
|
||||
current_position += z_size_deserialized.second;
|
||||
// Deserialize the control/bounds values
|
||||
const std::pair<int64_t, uint64_t> stride1_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
stride1_ = stride1_deserialized.first;
|
||||
current_position += stride1_deserialized.second;
|
||||
const std::pair<int64_t, uint64_t> stride2_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
stride2_ = stride2_deserialized.first;
|
||||
current_position += stride2_deserialized.second;
|
||||
const std::pair<int64_t, uint64_t> num_x_cells_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
num_x_cells_ = num_x_cells_deserialized.first;
|
||||
current_position += num_x_cells_deserialized.second;
|
||||
const std::pair<int64_t, uint64_t> num_y_cells_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
num_y_cells_ = num_y_cells_deserialized.first;
|
||||
current_position += num_y_cells_deserialized.second;
|
||||
const std::pair<int64_t, uint64_t> num_z_cells_deserialized = arc_utilities::DeserializeFixedSizePOD<int64_t>(buffer, current_position);
|
||||
num_z_cells_ = num_z_cells_deserialized.first;
|
||||
current_position += num_z_cells_deserialized.second;
|
||||
// Deserialize the default value
|
||||
const std::pair<T, uint64_t> default_value_deserialized = value_deserializer(buffer, current_position);
|
||||
default_value_ = default_value_deserialized.first;
|
||||
current_position += default_value_deserialized.second;
|
||||
// Deserialize the OOB value
|
||||
const std::pair<T, uint64_t> oob_value_deserialized = value_deserializer(buffer, current_position);
|
||||
oob_value_ = oob_value_deserialized.first;
|
||||
current_position += oob_value_deserialized.second;
|
||||
// Figure out how many bytes were read
|
||||
const uint64_t bytes_read = current_position - current;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
inline bool IsInitialized() const
|
||||
{
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
inline void ResetWithDefault()
|
||||
{
|
||||
SetContents(default_value_);
|
||||
}
|
||||
|
||||
inline void ResetWithNewValue(const T& new_value)
|
||||
{
|
||||
SetContents(new_value);
|
||||
}
|
||||
|
||||
inline void ResetWithNewDefault(const T& new_default)
|
||||
{
|
||||
default_value_ = new_default;
|
||||
SetContents(default_value_);
|
||||
}
|
||||
|
||||
inline bool IndexInBounds(const int64_t x_index, const int64_t y_index, const int64_t z_index) const
|
||||
{
|
||||
if (x_index >= 0 && y_index >= 0 && z_index >= 0 && x_index < num_x_cells_ && y_index < num_y_cells_ && z_index < num_z_cells_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<const T&, bool> GetImmutable3d(const Eigen::Vector3d& location) const
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex3d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return GetImmutable(indices[0], indices[1], indices[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<const T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<const T&, bool> GetImmutable4d(const Eigen::Vector4d& location) const
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex4d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return GetImmutable(indices[0], indices[1], indices[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<const T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<const T&, bool> GetImmutable(const double x, const double y, const double z) const
|
||||
{
|
||||
const Eigen::Vector4d location(x, y, z, 1.0);
|
||||
return GetImmutable4d(location);
|
||||
}
|
||||
|
||||
inline std::pair<const T&, bool> GetImmutable(const GRID_INDEX& index) const
|
||||
{
|
||||
return GetImmutable(index.x, index.y, index.z);
|
||||
}
|
||||
|
||||
inline std::pair<const T&, bool> GetImmutable(const int64_t x_index, const int64_t y_index, const int64_t z_index) const
|
||||
{
|
||||
assert(initialized_);
|
||||
if (IndexInBounds(x_index, y_index, z_index))
|
||||
{
|
||||
const int64_t data_index = GetDataIndex(x_index, y_index, z_index);
|
||||
assert(data_index >= 0 && data_index < (int64_t)data_.size());
|
||||
return std::pair<const T&, bool>(data_[data_index], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<const T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<T&, bool> GetMutable3d(const Eigen::Vector3d& location)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex3d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return GetMutable(indices[0], indices[1], indices[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<T&, bool> GetMutable4d(const Eigen::Vector4d& location)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex4d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return GetMutable(indices[0], indices[1], indices[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<T&, bool> GetMutable(const double x, const double y, const double z)
|
||||
{
|
||||
const Eigen::Vector4d location(x, y, z, 1.0);
|
||||
return GetMutable4d(location);
|
||||
}
|
||||
|
||||
inline std::pair<T&, bool> GetMutable(const GRID_INDEX& index)
|
||||
{
|
||||
return GetMutable(index.x, index.y, index.z);
|
||||
}
|
||||
|
||||
inline std::pair<T&, bool> GetMutable(const int64_t x_index, const int64_t y_index, const int64_t z_index)
|
||||
{
|
||||
assert(initialized_);
|
||||
if (IndexInBounds(x_index, y_index, z_index))
|
||||
{
|
||||
const int64_t data_index = GetDataIndex(x_index, y_index, z_index);
|
||||
assert(data_index >= 0 && data_index < (int64_t)data_.size());
|
||||
return std::pair<T&, bool>(data_[data_index], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<T&, bool>(oob_value_, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue3d(const Eigen::Vector3d& location, const T& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex3d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return SetValue(indices[0], indices[1], indices[2], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue4d(const Eigen::Vector4d& location, const T& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex4d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return SetValue(indices[0], indices[1], indices[2], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue(const double x, const double y, const double z, const T& value)
|
||||
{
|
||||
const Eigen::Vector4d location(x, y, z, 1.0);
|
||||
return SetValue4d(location, value);
|
||||
}
|
||||
|
||||
inline bool SetValue(const GRID_INDEX& index, const T& value)
|
||||
{
|
||||
return SetValue(index.x, index.y, index.z, value);
|
||||
}
|
||||
|
||||
inline bool SetValue(const int64_t x_index, const int64_t y_index, const int64_t z_index, const T& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
if (IndexInBounds(x_index, y_index, z_index))
|
||||
{
|
||||
const int64_t data_index = GetDataIndex(x_index, y_index, z_index);
|
||||
assert(data_index >= 0 && data_index < (int64_t)data_.size());
|
||||
data_[data_index] = value;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue3d(const Eigen::Vector3d& location, T&& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex3d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return SetValue(indices[0], indices[1], indices[2], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue4d(const Eigen::Vector4d& location, T&& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
const std::vector<int64_t> indices = LocationToGridIndex4d(location);
|
||||
if (indices.size() == 3)
|
||||
{
|
||||
return SetValue(indices[0], indices[1], indices[2], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SetValue(const double x, const double y, const double z, T&& value)
|
||||
{
|
||||
const Eigen::Vector4d location(x, y, z, 1.0);
|
||||
return SetValue4d(location, value);
|
||||
}
|
||||
|
||||
inline bool SetValue(const GRID_INDEX& index, T&& value)
|
||||
{
|
||||
return SetValue(index.x, index.y, index.z, value);
|
||||
}
|
||||
|
||||
inline bool SetValue(const int64_t x_index, const int64_t y_index, const int64_t z_index, T&& value)
|
||||
{
|
||||
assert(initialized_);
|
||||
if (IndexInBounds(x_index, y_index, z_index))
|
||||
{
|
||||
const int64_t data_index = GetDataIndex(x_index, y_index, z_index);
|
||||
assert(data_index >= 0 && data_index < (int64_t)data_.size());
|
||||
data_[data_index] = value;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline double GetXSize() const
|
||||
{
|
||||
return x_size_;
|
||||
}
|
||||
|
||||
inline double GetYSize() const
|
||||
{
|
||||
return y_size_;
|
||||
}
|
||||
|
||||
inline double GetZSize() const
|
||||
{
|
||||
return z_size_;
|
||||
}
|
||||
|
||||
inline std::vector<double> GetCellSizes() const
|
||||
{
|
||||
return std::vector<double>{cell_x_size_, cell_y_size_, cell_z_size_};
|
||||
}
|
||||
|
||||
inline T GetDefaultValue() const
|
||||
{
|
||||
return default_value_;
|
||||
}
|
||||
|
||||
inline T GetOOBValue() const
|
||||
{
|
||||
return oob_value_;
|
||||
}
|
||||
|
||||
inline void SetDefaultValue(const T& default_value)
|
||||
{
|
||||
default_value_ = default_value;
|
||||
}
|
||||
|
||||
inline void SetOOBValue(const T& oob_value)
|
||||
{
|
||||
oob_value_ = oob_value;
|
||||
}
|
||||
|
||||
inline int64_t GetNumXCells() const
|
||||
{
|
||||
return num_x_cells_;
|
||||
}
|
||||
|
||||
inline int64_t GetNumYCells() const
|
||||
{
|
||||
return num_y_cells_;
|
||||
}
|
||||
|
||||
inline int64_t GetNumZCells() const
|
||||
{
|
||||
return num_z_cells_;
|
||||
}
|
||||
|
||||
inline const Eigen::Isometry3d& GetOriginTransform() const
|
||||
{
|
||||
return origin_transform_;
|
||||
}
|
||||
|
||||
inline const Eigen::Isometry3d& GetInverseOriginTransform() const
|
||||
{
|
||||
return inverse_origin_transform_;
|
||||
}
|
||||
|
||||
inline std::vector<int64_t> LocationToGridIndex(const double x, const double y, const double z) const
|
||||
{
|
||||
const Eigen::Vector4d point(x, y, z, 1.0);
|
||||
return LocationToGridIndex4d(point);
|
||||
}
|
||||
|
||||
inline std::vector<int64_t> LocationToGridIndex3d(const Eigen::Vector3d& location) const
|
||||
{
|
||||
assert(initialized_);
|
||||
const Eigen::Vector3d point_in_grid_frame = inverse_origin_transform_ * location;
|
||||
const int64_t x_cell = (int64_t)(point_in_grid_frame.x() * inv_cell_x_size_);
|
||||
const int64_t y_cell = (int64_t)(point_in_grid_frame.y() * inv_cell_y_size_);
|
||||
const int64_t z_cell = (int64_t)(point_in_grid_frame.z() * inv_cell_z_size_);
|
||||
if (IndexInBounds(x_cell, y_cell, z_cell))
|
||||
{
|
||||
return std::vector<int64_t>{x_cell, y_cell, z_cell};
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::vector<int64_t>();
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<int64_t> LocationToGridIndex4d(const Eigen::Vector4d& location) const
|
||||
{
|
||||
assert(initialized_);
|
||||
const Eigen::Vector4d point_in_grid_frame = inverse_origin_transform_ * location;
|
||||
const int64_t x_cell = (int64_t)(point_in_grid_frame(0) * inv_cell_x_size_);
|
||||
const int64_t y_cell = (int64_t)(point_in_grid_frame(1) * inv_cell_y_size_);
|
||||
const int64_t z_cell = (int64_t)(point_in_grid_frame(2) * inv_cell_z_size_);
|
||||
if (IndexInBounds(x_cell, y_cell, z_cell))
|
||||
{
|
||||
return std::vector<int64_t>{x_cell, y_cell, z_cell};
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::vector<int64_t>();
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<double> GridIndexToLocation(const GRID_INDEX& index) const
|
||||
{
|
||||
return GridIndexToLocation(index.x, index.y, index.z);
|
||||
}
|
||||
|
||||
inline std::vector<double> GridIndexToLocation(const int64_t x_index, const int64_t y_index, const int64_t z_index) const
|
||||
{
|
||||
assert(initialized_);
|
||||
if (IndexInBounds(x_index, y_index, z_index))
|
||||
{
|
||||
const Eigen::Vector3d point_in_grid_frame(cell_x_size_ * ((double)x_index + 0.5), cell_y_size_ * ((double)y_index + 0.5), cell_z_size_ * ((double)z_index + 0.5));
|
||||
const Eigen::Vector3d point = origin_transform_ * point_in_grid_frame;
|
||||
return std::vector<double>{point.x(), point.y(), point.z()};
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::vector<double>();
|
||||
}
|
||||
}
|
||||
|
||||
inline const std::vector<T>& GetRawData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline std::vector<T> CopyRawData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline bool SetRawData(std::vector<T>& data)
|
||||
{
|
||||
assert(initialized_);
|
||||
const int64_t expected_length = num_x_cells_ * num_y_cells_ * num_z_cells_;
|
||||
if ((int64_t)data.size() == expected_length)
|
||||
{
|
||||
data_ = data;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to load internal data - expected " << expected_length << " got " << data.size() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t HashDataIndex(const int64_t x_index, const int64_t y_index, const int64_t z_index) const
|
||||
{
|
||||
return (x_index * stride1_) + (y_index * stride2_) + z_index;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<VoxelGrid::GRID_INDEX>
|
||||
{
|
||||
std::size_t operator()(const VoxelGrid::GRID_INDEX& index) const
|
||||
{
|
||||
using std::size_t;
|
||||
using std::hash;
|
||||
return ((std::hash<int64_t>()(index.x) ^ (std::hash<int64_t>()(index.y) << 1) >> 1) ^ (std::hash<int64_t>()(index.z) << 1));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& strm, const VoxelGrid::GRID_INDEX& index)
|
||||
{
|
||||
strm << "GridIndex: " << index.x << "," << index.y << "," << index.z;
|
||||
return strm;
|
||||
}
|
||||
|
||||
#endif // VOXEL_GRID_HPP
|
||||
25
flightlib/third_party/arc_utilities/include/arc_utilities/zlib_helpers.hpp
vendored
Normal file
25
flightlib/third_party/arc_utilities/include/arc_utilities/zlib_helpers.hpp
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifndef ZLIB_HELPERS_HPP
|
||||
#define ZLIB_HELPERS_HPP
|
||||
|
||||
namespace ZlibHelpers
|
||||
{
|
||||
std::vector<uint8_t> DecompressBytes(const std::vector<uint8_t>& compressed);
|
||||
|
||||
std::vector<uint8_t> CompressBytes(const std::vector<uint8_t>& uncompressed);
|
||||
|
||||
std::vector<uint8_t> LoadFromFileAndDecompress(const std::string& path);
|
||||
|
||||
void CompressAndWriteToFile(const std::vector<uint8_t>& uncompressed, const std::string& path);
|
||||
}
|
||||
|
||||
#endif // ZLIB_HELPERS_HPP
|
||||
Reference in New Issue
Block a user