add backend

This commit is contained in:
Han-Sin
2025-07-20 12:46:40 +08:00
parent 3a6c6a9a97
commit a9c0a5975c
108 changed files with 576799 additions and 28 deletions

View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2018, sikang
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.8.3)
project(decomp_ros_msgs)
find_package(catkin_simple REQUIRED)
catkin_simple()
cs_install()
cs_export()

View File

@@ -0,0 +1,2 @@
float64[3] d
float64[9] E

View File

@@ -0,0 +1,2 @@
Header header
Ellipsoid[] ellipsoids

View File

@@ -0,0 +1,2 @@
geometry_msgs/Point[] points
geometry_msgs/Point[] normals #norm is an outer vector

View File

@@ -0,0 +1,2 @@
Header header
Polyhedron[] polyhedrons

View File

@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<package format="2">
<name>decomp_ros_msgs</name>
<version>0.0.0</version>
<description>The decomp_ros_msgs package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
<maintainer email="sikang@seas.upenn.edu">sikang</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>catkin_simple</build_depend>
<depend>geometry_msgs</depend>
<depend>message_generation</depend>
<depend>message_runtime</depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>

View File

@@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 2.8.3)
project(decomp_ros_utils)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -Wall -Wno-deprecated-declarations")
find_package(catkin REQUIRED COMPONENTS rviz roscpp)
find_package(catkin_simple REQUIRED)
find_package(cmake_modules)
find_package(Eigen3 REQUIRED)
include_directories(${EIGEN3_INCLUDE_DIRS} ${DECOMP_UTIL_INCLUDE_DIRS})
add_definitions(-DQT_NO_KEYWORDS)
## This setting causes Qt's "MOC" generation to happen automatically.
## this does not moc things in include!!!!!!! only in src
set(CMAKE_AUTOMOC ON)
## We'll use the version that rviz used so they are compatible.
if(rviz_QT_VERSION VERSION_LESS "5")
message(STATUS "Using Qt4 based on the rviz_QT_VERSION: ${rviz_QT_VERSION}")
find_package(Qt4 ${rviz_QT_VERSION} EXACT REQUIRED QtCore QtGui)
include(${QT_USE_FILE})
else()
message(STATUS "Using Qt5 based on the rviz_QT_VERSION: ${rviz_QT_VERSION}")
find_package(Qt5 ${rviz_QT_VERSION} EXACT REQUIRED Core Widgets)
set(QT_LIBRARIES Qt5::Widgets)
endif()
catkin_simple()
set(SOURCE_FILES
src/bound_visual.cpp
src/mesh_visual.cpp
src/vector_visual.cpp
src/ellipsoid_array_visual.cpp
src/ellipsoid_array_display.cpp
src/polyhedron_array_display.cpp
${MOC_FILES})
cs_add_library(decomp_rviz_plugins ${SOURCE_FILES})
target_link_libraries(decomp_rviz_plugins ${QT_LIBRARIES} ${catkin_LIBRARIES} ${rviz_DEFAULT_PLUGIN_LIBRARIES})
cs_install()
cs_export()

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

View File

@@ -0,0 +1,130 @@
/**
* @file data_type.h
* @brief Defines all data types used in this lib
* Mostly alias from Eigen Library.
*/
#include <stdio.h>
#include <math.h>
#include <limits>
#include <vector>
#include <Eigen/Geometry>
#include <Eigen/StdVector>
///Set red font in printf funtion
#ifndef ANSI_COLOR_RED
#define ANSI_COLOR_RED "\x1b[1;31m"
#endif
///Set green font in printf funtion
#ifndef ANSI_COLOR_GREEN
#define ANSI_COLOR_GREEN "\x1b[1;32m"
#endif
///Set yellow font in printf funtion
#ifndef ANSI_COLOR_YELLOW
#define ANSI_COLOR_YELLOW "\x1b[1;33m"
#endif
///Set blue font in printf funtion
#ifndef ANSI_COLOR_BLUE
#define ANSI_COLOR_BLUE "\x1b[1;34m"
#endif
///Set magenta font in printf funtion
#ifndef ANSI_COLOR_MAGENTA
#define ANSI_COLOR_MAGENTA "\x1b[1;35m"
#endif
///Set cyan font in printf funtion
#ifndef ANSI_COLOR_CYAN
#define ANSI_COLOR_CYAN "\x1b[1;36m"
#endif
///Reset font color in printf funtion
#ifndef ANSI_COLOR_RESET
#define ANSI_COLOR_RESET "\x1b[0m"
#endif
#ifndef DATA_TYPE_H
#define DATA_TYPE_H
/*! \brief Rename the float type used in lib
Default is set to be double, but user can change it to float.
*/
typedef double decimal_t;
///Pre-allocated std::vector for Eigen using vec_E
template <typename T>
using vec_E = std::vector<T, Eigen::aligned_allocator<T>>;
///Eigen 1D float vector
template <int N>
using Vecf = Eigen::Matrix<decimal_t, N, 1>;
///Eigen 1D int vector
template <int N>
using Veci = Eigen::Matrix<int, N, 1>;
///MxN Eigen matrix
template <int M, int N>
using Matf = Eigen::Matrix<decimal_t, M, N>;
///MxN Eigen matrix with M unknown
template <int N>
using MatDNf = Eigen::Matrix<decimal_t, Eigen::Dynamic, N>;
///Vector of Eigen 1D float vector
template <int N>
using vec_Vecf = vec_E<Vecf<N>>;
///Vector of Eigen 1D int vector
template <int N>
using vec_Veci = vec_E<Veci<N>>;
///Eigen 1D float vector of size 2
typedef Vecf<2> Vec2f;
///Eigen 1D int vector of size 2
typedef Veci<2> Vec2i;
///Eigen 1D float vector of size 3
typedef Vecf<3> Vec3f;
///Eigen 1D int vector of size 3
typedef Veci<3> Vec3i;
///Eigen 1D float vector of size 4
typedef Vecf<4> Vec4f;
///Column vector in float of size 6
typedef Vecf<6> Vec6f;
///Vector of type Vec2f.
typedef vec_E<Vec2f> vec_Vec2f;
///Vector of type Vec2i.
typedef vec_E<Vec2i> vec_Vec2i;
///Vector of type Vec3f.
typedef vec_E<Vec3f> vec_Vec3f;
///Vector of type Vec3i.
typedef vec_E<Vec3i> vec_Vec3i;
///2x2 Matrix in float
typedef Matf<2, 2> Mat2f;
///3x3 Matrix in float
typedef Matf<3, 3> Mat3f;
///4x4 Matrix in float
typedef Matf<4, 4> Mat4f;
///6x6 Matrix in float
typedef Matf<6, 6> Mat6f;
///Dynamic Nx1 Eigen float vector
typedef Vecf<Eigen::Dynamic> VecDf;
///Nx2 Eigen float matrix
typedef MatDNf<2> MatD2f;
///Nx3 Eigen float matrix
typedef MatDNf<3> MatD3f;
///Dynamic MxN Eigen float matrix
typedef Matf<Eigen::Dynamic, Eigen::Dynamic> MatDf;
///Allias of Eigen::Affine2d
typedef Eigen::Transform<decimal_t, 2, Eigen::Affine> Aff2f;
///Allias of Eigen::Affine3d
typedef Eigen::Transform<decimal_t, 3, Eigen::Affine> Aff3f;
#endif
#ifndef EIGEN_QUAT
#define EIGEN_QUAT
///Allias of Eigen::Quaterniond
typedef Eigen::Quaternion<decimal_t> Quatf;
#endif
#ifndef EIGEN_EPSILON
#define EIGEN_EPSILON
///Compensate for numerical error
constexpr decimal_t epsilon_ = 1e-10; // numerical calculation error
#endif

View File

@@ -0,0 +1,36 @@
/**
* @file data_utils.h
* @brief Provide a few widely used function for basic type
*/
#ifndef DATA_UTILS_H
#define DATA_UTILS_H
#include <decomp_basis/data_type.h>
///Template for transforming a vector
template <class T, class TF>
vec_E<T> transform_vec(const vec_E<T> &t, const TF &tf) {
vec_E<T> new_t;
for (const auto &it : t)
new_t.push_back(tf * it);
return new_t;
}
///Template for calculating distance
template <class T>
decimal_t total_distance(const vec_E<T>& vs){
decimal_t dist = 0;
for(unsigned int i = 1; i < vs.size(); i++)
dist += (vs[i] - vs[i-1]).norm();
return dist;
}
///Transform all entries in a vector using given TF
#define transform_vec3 transform_vec<Vec3f, Aff3f>
///Sum up total distance for Vec3f
#define total_distance3f total_distance<Vec3f>
///Sum up total distance for Vec3i
#define total_distance3i total_distance<Vec3i>
#endif

View File

@@ -0,0 +1,102 @@
/**
* @file ellipsoid.h
* @brief Ellipsoid class
*/
#ifndef DECOMP_ELLIPSOID_H
#define DECOMP_ELLIPSOID_H
#include <iostream>
#include <decomp_basis/data_type.h>
#include <decomp_geometry/polyhedron.h>
template <int Dim>
struct Ellipsoid {
Ellipsoid() {}
Ellipsoid(const Matf<Dim, Dim>& C, const Vecf<Dim>& d) : C_(C), d_(d) {}
/// Calculate distance to the center
decimal_t dist(const Vecf<Dim>& pt) const {
return (C_.inverse() * (pt - d_)).norm();
}
/// Check if the point is inside, non-exclusive
bool inside(const Vecf<Dim>& pt) const {
return dist(pt) <= 1;
}
/// Calculate points inside ellipsoid, non-exclusive
vec_Vecf<Dim> points_inside(const vec_Vecf<Dim> &O) const {
vec_Vecf<Dim> new_O;
for (const auto &it : O) {
if (inside(it))
new_O.push_back(it);
}
return new_O;
}
///Find the closest point
Vecf<Dim> closest_point(const vec_Vecf<Dim> &O) const {
Vecf<Dim> pt = Vecf<Dim>::Zero();
decimal_t min_dist = std::numeric_limits<decimal_t>::max();
for (const auto &it : O) {
decimal_t d = dist(it);
if (d < min_dist) {
min_dist = d;
pt = it;
}
}
return pt;
}
///Find the closest hyperplane from the closest point
Hyperplane<Dim> closest_hyperplane(const vec_Vecf<Dim> &O) const {
const auto closest_pt = closest_point(O);
const auto n = C_.inverse() * C_.inverse().transpose() *
(closest_pt - d_);
return Hyperplane<Dim>(closest_pt, n.normalized());
}
/// Sample n points along the contour
template<int U = Dim>
typename std::enable_if<U == 2, vec_Vecf<U>>::type
sample(int num) const {
vec_Vecf<Dim> pts;
decimal_t dyaw = M_PI*2/num;
for(decimal_t yaw = 0; yaw < M_PI*2; yaw+=dyaw) {
Vecf<Dim> pt;
pt << cos(yaw), sin(yaw);
pts.push_back(C_ * pt + d_);
}
return pts;
}
void print() const {
std::cout << "C: " << C_ << std::endl;
std::cout << "d: " << d_ << std::endl;
}
/// Get ellipsoid volume
decimal_t volume() const {
return C_.determinant();
}
/// Get C matrix
Matf<Dim, Dim> C() const {
return C_;
}
/// Get center
Vecf<Dim> d() const {
return d_;
}
Matf<Dim, Dim> C_;
Vecf<Dim> d_;
};
typedef Ellipsoid<2> Ellipsoid2D;
typedef Ellipsoid<3> Ellipsoid3D;
#endif

View File

@@ -0,0 +1,258 @@
/**
* @file geometric_utils.h
* @brief basic geometry utils
*/
#ifndef DECOMP_GEOMETRIC_UTILS_H
#define DECOMP_GEOMETRIC_UTILS_H
#include <Eigen/Eigenvalues>
#include <decomp_basis/data_utils.h>
#include <decomp_geometry/polyhedron.h>
#include <iostream>
/// Calculate eigen values
template <int Dim> Vecf<Dim> eigen_value(const Matf<Dim, Dim> &A) {
Eigen::SelfAdjointEigenSolver<Matf<Dim, Dim>> es(A);
return es.eigenvalues();
}
/// Calculate rotation matrix from a vector (aligned with x-axis)
inline Mat2f vec2_to_rotation(const Vec2f &v) {
decimal_t yaw = std::atan2(v(1), v(0));
Mat2f R;
R << cos(yaw), -sin(yaw), sin(yaw), cos(yaw);
return R;
}
inline Mat3f vec3_to_rotation(const Vec3f &v) {
// zero roll
Vec3f rpy(0, std::atan2(-v(2), v.topRows<2>().norm()),
std::atan2(v(1), v(0)));
Quatf qx(cos(rpy(0) / 2), sin(rpy(0) / 2), 0, 0);
Quatf qy(cos(rpy(1) / 2), 0, sin(rpy(1) / 2), 0);
Quatf qz(cos(rpy(2) / 2), 0, 0, sin(rpy(2) / 2));
return Mat3f(qz * qy * qx);
}
/// Sort plannar points in the counter-clockwise order
inline vec_Vec2f sort_pts(const vec_Vec2f &pts) {
/// if empty, dont sort
if (pts.empty())
return pts;
/// calculate center point
Vec2f avg = Vec2f::Zero();
for (const auto &pt : pts)
avg += pt;
avg /= pts.size();
/// sort in body frame
vec_E<std::pair<decimal_t, Vec2f>> pts_valued;
pts_valued.resize(pts.size());
for (unsigned int i = 0; i < pts.size(); i++) {
decimal_t theta = atan2(pts[i](1) - avg(1), pts[i](0) - avg(0));
pts_valued[i] = std::make_pair(theta, pts[i]);
}
std::sort(
pts_valued.begin(), pts_valued.end(),
[](const std::pair<decimal_t, Vec2f> &i,
const std::pair<decimal_t, Vec2f> &j) { return i.first < j.first; });
vec_Vec2f pts_sorted(pts_valued.size());
for (size_t i = 0; i < pts_valued.size(); i++)
pts_sorted[i] = pts_valued[i].second;
return pts_sorted;
}
/// Find intersection between two lines on the same plane, return false if they
/// are not intersected
inline bool line_intersect(const std::pair<Vec2f, Vec2f> &v1,
const std::pair<Vec2f, Vec2f> &v2, Vec2f &pi) {
decimal_t a1 = -v1.first(1);
decimal_t b1 = v1.first(0);
decimal_t c1 = a1 * v1.second(0) + b1 * v1.second(1);
decimal_t a2 = -v2.first(1);
decimal_t b2 = v2.first(0);
decimal_t c2 = a2 * v2.second(0) + b2 * v2.second(1);
decimal_t x = (c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1);
decimal_t y = (c1 * a2 - c2 * a1) / (a2 * b1 - a1 * b2);
if (std::isnan(x) || std::isnan(y) || std::isinf(x) || std::isinf(y))
return false;
else {
pi << x, y;
return true;
}
}
/// Find intersection between multiple lines
inline vec_Vec2f line_intersects(const vec_E<std::pair<Vec2f, Vec2f>> &lines) {
vec_Vec2f pts;
for (unsigned int i = 0; i < lines.size(); i++) {
for (unsigned int j = i + 1; j < lines.size(); j++) {
Vec2f pi;
if (line_intersect(lines[i], lines[j], pi)) {
pts.push_back(pi);
}
}
}
return pts;
}
/// Find extreme points of Polyhedron2D
inline vec_Vec2f cal_vertices(const Polyhedron2D &poly) {
vec_E<std::pair<Vec2f, Vec2f>> lines;
const auto vs = poly.hyperplanes();
for (unsigned int i = 0; i < vs.size(); i++) {
Vec2f n = vs[i].n_;
Vec2f v(-n(1), n(0));
v = v.normalized();
lines.push_back(std::make_pair(v, vs[i].p_));
/*
std::cout << "add p: " << lines.back().second.transpose() <<
" v: " << lines.back().first.transpose() << std::endl;
*/
}
auto vts = line_intersects(lines);
// for(const auto& it: vts)
// std::cout << "vertice: " << it.transpose() << std::endl;
vec_Vec2f vts_inside = poly.points_inside(vts);
vts_inside = sort_pts(vts_inside);
return vts_inside;
}
/// Find extreme points of Polyhedron3D
inline vec_E<vec_Vec3f> cal_vertices(const Polyhedron3D &poly) {
vec_E<vec_Vec3f> bds;
const auto vts = poly.hyperplanes();
//**** for each plane, find lines on it
for (unsigned int i = 0; i < vts.size(); i++) {
const Vec3f t = vts[i].p_;
const Vec3f n = vts[i].n_;
const Quatf q = Quatf::FromTwoVectors(Vec3f(0, 0, 1), n);
const Mat3f R(q); // body to world
vec_E<std::pair<Vec2f, Vec2f>> lines;
for (unsigned int j = 0; j < vts.size(); j++) {
if (j == i)
continue;
Vec3f nw = vts[j].n_;
Vec3f nb = R.transpose() * nw;
decimal_t bb = vts[j].p_.dot(nw) - nw.dot(t);
Vec2f v = Vec3f(0, 0, 1).cross(nb).topRows<2>(); // line direction
Vec2f p; // point on the line
if (nb(1) != 0)
p << 0, bb / nb(1);
else if (nb(0) != 0)
p << bb / nb(0), 0;
else
continue;
lines.push_back(std::make_pair(v, p));
}
//**** find all intersect points
vec_Vec2f pts = line_intersects(lines);
//**** filter out points inside polytope
vec_Vec2f pts_inside;
for (const auto &it : pts) {
Vec3f p = R * Vec3f(it(0), it(1), 0) + t; // convert to world frame
if (poly.inside(p))
pts_inside.push_back(it);
}
if (pts_inside.size() > 2) {
//**** sort in plane frame
pts_inside = sort_pts(pts_inside);
//**** transform to world frame
vec_Vec3f points_valid;
for (auto &it : pts_inside)
points_valid.push_back(R * Vec3f(it(0), it(1), 0) + t);
//**** insert resulting polygon
bds.push_back(points_valid);
}
}
return bds;
}
/// Get the convex hull of a 2D points array, use wrapping method
inline vec_Vec2f cal_convex_hull(const vec_Vec2f &pts) {
/// find left most point
Vec2f p0;
decimal_t min_x = std::numeric_limits<decimal_t>::infinity();
for (const auto &it : pts) {
if (min_x > it(0) || (min_x == it(0) && it(1) < p0(1))) {
min_x = it(0);
p0 = it;
}
}
vec_Vec2f vs;
vs.push_back(p0);
while (vs.back() != p0 || vs.size() == 1) {
const auto ref_pt = vs.back();
Vec2f end_pt = p0;
for (size_t i = 0; i < pts.size(); i++) {
if (pts[i] == ref_pt)
continue;
Vec2f dir = (pts[i] - ref_pt).normalized();
Hyperplane2D hp(ref_pt, Vec2f(-dir(1), dir(0)));
bool most_left_hp = true;
for (size_t j = 0; j < pts.size(); j++) {
if (hp.signed_dist(pts[j]) > 0 && pts[j] != pts[i] &&
pts[j] != ref_pt) {
// if(hp.signed_dist(pts[j]) > 0) {
most_left_hp = false;
break;
}
}
if (most_left_hp) {
end_pt = pts[i];
break;
}
}
// std::cout << "add: " << end_pt.transpose() << std::endl;
vs.push_back(end_pt);
}
return vs;
}
inline Polyhedron2D get_convex_hull(const vec_Vec2f &pts) {
Polyhedron2D poly;
Vec2f prev_dir(-1, -1);
for (size_t i = 0; i < pts.size() - 1; i++) {
size_t j = i + 1;
Vec2f dir = (pts[j] - pts[i]).normalized();
if (dir != prev_dir) {
poly.add(Hyperplane2D((pts[i] + pts[j]) / 2, Vec2f(-dir(1), dir(0))));
prev_dir = dir;
}
}
return poly;
}
/// Minkowski sum, add B to A with center Bc
inline Polyhedron2D minkowski_sum(const Polyhedron2D &A, const Polyhedron2D &B,
const Vec2f &Bc) {
const auto A_vertices = cal_vertices(A);
const auto B_vertices = cal_vertices(B);
vec_Vec2f C_vertices;
for (const auto &it : A_vertices) {
for (const auto &itt : B_vertices)
C_vertices.push_back(it + itt - Bc);
}
return get_convex_hull(cal_convex_hull(C_vertices));
}
#endif

View File

@@ -0,0 +1,154 @@
/**
* @file polygon.h
* @brief Polygon class
*/
#ifndef DECOMP_POLYGON_H
#define DECOMP_POLYGON_H
#include <decomp_basis/data_type.h>
///Hyperplane class
template <int Dim>
struct Hyperplane {
Hyperplane() {}
Hyperplane(const Vecf<Dim>& p, const Vecf<Dim>& n) : p_(p), n_(n) {}
/// Calculate the signed distance from point
decimal_t signed_dist(const Vecf<Dim>& pt) const {
return n_.dot(pt - p_);
}
/// Calculate the distance from point
decimal_t dist(const Vecf<Dim>& pt) const {
return std::abs(signed_dist(pt));
}
/// Point on the plane
Vecf<Dim> p_;
/// Normal of the plane, directional
Vecf<Dim> n_;
};
///Hyperplane2D: first is the point on the hyperplane, second is the normal
typedef Hyperplane<2> Hyperplane2D;
///Hyperplane3D: first is the point on the hyperplane, second is the normal
typedef Hyperplane<3> Hyperplane3D;
///Polyhedron class
template <int Dim>
struct Polyhedron {
///Null constructor
Polyhedron() {}
///Construct from Hyperplane array
Polyhedron(const vec_E<Hyperplane<Dim>>& vs) : vs_(vs) {}
///Append Hyperplane
void add(const Hyperplane<Dim>& v) {
vs_.push_back(v);
}
/// Check if the point is inside polyhedron, non-exclusive
bool inside(const Vecf<Dim>& pt) const {
for (const auto& v : vs_) {
if (v.signed_dist(pt) > epsilon_) {
//printf("rejected pt: (%f, %f), d: %f\n",pt(0), pt(1), v.signed_dist(pt));
return false;
}
}
return true;
}
/// Calculate points inside polyhedron, non-exclusive
vec_Vecf<Dim> points_inside(const vec_Vecf<Dim> &O) const {
vec_Vecf<Dim> new_O;
for (const auto &it : O) {
if (inside(it))
new_O.push_back(it);
}
return new_O;
}
/// Calculate normals, used for visualization
vec_E<std::pair<Vecf<Dim>, Vecf<Dim>>> cal_normals() const {
vec_E<std::pair<Vecf<Dim>, Vecf<Dim>>> ns(vs_.size());
for (size_t i = 0; i < vs_.size(); i++)
ns[i] = std::make_pair(vs_[i].p_, vs_[i].n_); // fist is point, second is normal
return ns;
}
/// Get the hyperplane array
vec_E<Hyperplane<Dim>> hyperplanes() const {
return vs_;
}
/// Hyperplane array
vec_E<Hyperplane<Dim>> vs_; // normal must go outside
};
///Polyhedron2D, consists of 2D hyperplane
typedef Polyhedron<2> Polyhedron2D;
///Polyhedron3D, consists of 3D hyperplane
typedef Polyhedron<3> Polyhedron3D;
///[A, b] for \f$Ax < b\f$
template <int Dim>
struct LinearConstraint {
///Null constructor
LinearConstraint() {}
/// Construct from \f$A, b\f$ directly, s.t \f$Ax < b\f$
LinearConstraint(const MatDNf<Dim>& A, const VecDf& b) : A_(A), b_(b) {}
/**
* @brief Construct from a inside point and hyperplane array
* @param p0 point that is inside
* @param vs hyperplane array, normal should go outside
*/
LinearConstraint(const Vecf<Dim> p0, const vec_E<Hyperplane<Dim>>& vs) {
const unsigned int size = vs.size();
MatDNf<Dim> A(size, Dim);
VecDf b(size);
for (unsigned int i = 0; i < size; i++) {
auto n = vs[i].n_;
decimal_t c = vs[i].p_.dot(n);
if (n.dot(p0) - c > 0) {
n = -n;
c = -c;
}
A.row(i) = n;
b(i) = c;
}
A_ = A;
b_ = b;
}
/// Check if the point is inside polyhedron using linear constraint
bool inside(const Vecf<Dim> &pt) {
VecDf d = A_ * pt - b_;
for (unsigned int i = 0; i < d.rows(); i++) {
if (d(i) > 0)
return false;
}
return true;
}
/// Get \f$A\f$ matrix
MatDNf<Dim> A() const { return A_; }
/// Get \f$b\f$ matrix
VecDf b() const { return b_; }
MatDNf<Dim> A_;
VecDf b_;
};
///LinearConstraint 2D
typedef LinearConstraint<2> LinearConstraint2D;
///LinearConstraint 3D
typedef LinearConstraint<3> LinearConstraint3D;
#endif

View File

@@ -0,0 +1,160 @@
#ifndef DECOMP_ROS_UTILS_H
#define DECOMP_ROS_UTILS_H
#include <decomp_geometry/ellipsoid.h>
#include <decomp_geometry/polyhedron.h>
#include <sensor_msgs/PointCloud.h>
#include <decomp_ros_msgs/PolyhedronArray.h>
#include <decomp_ros_msgs/EllipsoidArray.h>
#include <nav_msgs/Path.h>
namespace DecompROS {
template <int Dim> nav_msgs::Path vec_to_path(const vec_Vecf<Dim> &vs) {
nav_msgs::Path path;
for (const auto& it : vs) {
geometry_msgs::PoseStamped pose;
pose.pose.position.x = it(0);
pose.pose.position.y = it(1);
pose.pose.position.z = Dim == 2 ? 0 : it(2);
pose.pose.orientation.w = 1.0;
pose.pose.orientation.x = 0.0;
pose.pose.orientation.y = 0.0;
pose.pose.orientation.z = 0.0;
path.poses.push_back(pose);
}
return path;
}
inline sensor_msgs::PointCloud vec_to_cloud(const vec_Vec3f &pts) {
sensor_msgs::PointCloud cloud;
cloud.points.resize(pts.size());
for (unsigned int i = 0; i < pts.size(); i++) {
cloud.points[i].x = pts[i](0);
cloud.points[i].y = pts[i](1);
cloud.points[i].z = pts[i](2);
}
return cloud;
}
inline vec_Vec3f cloud_to_vec(const sensor_msgs::PointCloud &cloud) {
vec_Vec3f pts;
pts.resize(cloud.points.size());
for (unsigned int i = 0; i < cloud.points.size(); i++) {
pts[i](0) = cloud.points[i].x;
pts[i](1) = cloud.points[i].y;
pts[i](2) = cloud.points[i].z;
}
return pts;
}
inline Polyhedron3D ros_to_polyhedron(const decomp_ros_msgs::Polyhedron& msg){
Polyhedron3D poly;
for(unsigned int i = 0; i < msg.points.size(); i++){
Vec3f pt(msg.points[i].x,
msg.points[i].y,
msg.points[i].z);
Vec3f n(msg.normals[i].x,
msg.normals[i].y,
msg.normals[i].z);
poly.add(Hyperplane3D(pt, n));
}
return poly;
}
inline vec_E<Polyhedron3D> ros_to_polyhedron_array(const decomp_ros_msgs::PolyhedronArray& msg) {
vec_E<Polyhedron3D> polys(msg.polyhedrons.size());
for(size_t i = 0; i < msg.polyhedrons.size(); i++)
polys[i] = ros_to_polyhedron(msg.polyhedrons[i]);
return polys;
}
inline decomp_ros_msgs::Polyhedron polyhedron_to_ros(const Polyhedron2D& poly){
decomp_ros_msgs::Polyhedron msg;
for (const auto &p : poly.hyperplanes()) {
geometry_msgs::Point pt, n;
pt.x = p.p_(0);
pt.y = p.p_(1);
pt.z = 0;
n.x = p.n_(0);
n.y = p.n_(1);
n.z = 0;
msg.points.push_back(pt);
msg.normals.push_back(n);
}
geometry_msgs::Point pt1, n1;
pt1.x = 0, pt1.y = 0, pt1.z = 0.01;
n1.x = 0, n1.y = 0, n1.z = 1;
msg.points.push_back(pt1);
msg.normals.push_back(n1);
geometry_msgs::Point pt2, n2;
pt2.x = 0, pt2.y = 0, pt2.z = -0.01;
n2.x = 0, n2.y = 0, n2.z = -1;
msg.points.push_back(pt2);
msg.normals.push_back(n2);
return msg;
}
inline decomp_ros_msgs::Polyhedron polyhedron_to_ros(const Polyhedron3D& poly){
decomp_ros_msgs::Polyhedron msg;
for (const auto &p : poly.hyperplanes()) {
geometry_msgs::Point pt, n;
pt.x = p.p_(0);
pt.y = p.p_(1);
pt.z = p.p_(2);
n.x = p.n_(0);
n.y = p.n_(1);
n.z = p.n_(2);
msg.points.push_back(pt);
msg.normals.push_back(n);
}
return msg;
}
template <int Dim>
decomp_ros_msgs::PolyhedronArray polyhedron_array_to_ros(const vec_E<Polyhedron<Dim>>& vs){
decomp_ros_msgs::PolyhedronArray msg;
for (const auto &v : vs)
msg.polyhedrons.push_back(polyhedron_to_ros(v));
return msg;
}
template <int Dim>
decomp_ros_msgs::EllipsoidArray ellipsoid_array_to_ros(const vec_E<Ellipsoid<Dim>>& Es) {
decomp_ros_msgs::EllipsoidArray ellipsoids;
for (unsigned int i = 0; i < Es.size(); i++) {
decomp_ros_msgs::Ellipsoid ellipsoid;
auto d = Es[i].d();
ellipsoid.d[0] = d(0);
ellipsoid.d[1] = d(1);
ellipsoid.d[2] = Dim == 2 ? 0:d(2);
auto C = Es[i].C();
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if(x < Dim && y < Dim)
ellipsoid.E[3 * x + y] = C(x, y);
else
ellipsoid.E[3 * x + y] = 0;
}
}
ellipsoids.ellipsoids.push_back(ellipsoid);
}
return ellipsoids;
}
}
#endif

View File

@@ -0,0 +1,96 @@
/**
* @file decomp_base.h
* @brief Decomp Base Class
*/
#ifndef DECOMP_BASE_H
#define DECOMP_BASE_H
#include <decomp_geometry/ellipsoid.h>
#include <decomp_geometry/polyhedron.h>
//#include <decomp_geometry/geometry_utils.h>
/**
* @brief Line Segment Class
*
* The basic element in EllipsoidDecomp
*/
template <int Dim>
class DecompBase {
public:
///Null constructor
DecompBase() {}
/**
* @brief Adding local bounding box around line seg
* @param Dim Distance in corresponding axis
*
* This virtual bounding box is parallel to the line segment, the x,y,z axes are not w.r.t the world coordinate system, but instead, x-axis is parallel to the line, y-axis is perpendicular to the line and world z-axis, z-axis is perpendiculat to the line and y-axis
*/
void set_local_bbox(const Vecf<Dim>& bbox) {
local_bbox_ = bbox;
}
///Import obstacle points
void set_obs(const vec_Vecf<Dim> &obs) {
// only consider points inside local bbox
Polyhedron<Dim> vs;
add_local_bbox(vs);
obs_ = vs.points_inside(obs);
}
///Get obstacel points
vec_Vecf<Dim> get_obs() const { return obs_; }
///Get ellipsoid
Ellipsoid<Dim> get_ellipsoid() const { return ellipsoid_; }
///Get polyhedron
Polyhedron<Dim> get_polyhedron() const { return polyhedron_; }
/**
* @brief Inflate the line segment
* @param radius the offset added to the long semi-axis
*/
virtual void dilate(decimal_t radius = 0) = 0;
/**
* @brief Shrink the polyhedron
* @param shrink_distance Shrink distance
*/
virtual void shrink(double shrink_distance) {}
protected:
virtual void add_local_bbox(Polyhedron<Dim> &Vs) = 0;
void find_polyhedron() {
//**** find half-space
Polyhedron<Dim> Vs;
vec_Vecf<Dim> obs_remain = obs_;
while (!obs_remain.empty()) {
const auto v = ellipsoid_.closest_hyperplane(obs_remain);
Vs.add(v);
vec_Vecf<Dim> obs_tmp;
for (const auto &it : obs_remain) {
if (v.signed_dist(it) < 0)
obs_tmp.push_back(it);
}
obs_remain = obs_tmp;
/*
std::cout << "a: " << a.transpose() << std::endl;
std::cout << "b: " << b << std::endl;
*/
}
polyhedron_ = Vs;
}
/// Obstacles, input
vec_Vecf<Dim> obs_;
/// Output ellipsoid
Ellipsoid<Dim> ellipsoid_;
/// Output polyhedron
Polyhedron<Dim> polyhedron_;
/// Local bounding box along the line segment
Vecf<Dim> local_bbox_{Vecf<Dim>::Zero()};
};
#endif

View File

@@ -0,0 +1,134 @@
/**
* @file ellipsoid_decomp.h
* @brief EllipsoidDecomp Class
*/
#ifndef ELLIPSOID_DECOMP_H
#define ELLIPSOID_DECOMP_H
#include <memory>
#include <decomp_util/line_segment.h>
/**
* @brief EllipsoidDecomp Class
*
* EllipsoidDecomp takes input as a given path and find the Safe Flight Corridor around it using Ellipsoids
*/
template <int Dim>
class EllipsoidDecomp {
public:
///Simple constructor
EllipsoidDecomp() {}
/**
* @brief Basic constructor
* @param origin The origin of the global bounding box
* @param dim The dimension of the global bounding box
*/
EllipsoidDecomp(const Vecf<Dim> &origin, const Vecf<Dim> &dim) {
global_bbox_min_ = origin;
global_bbox_max_ = origin + dim;
}
///Set obstacle points
void set_obs(const vec_Vecf<Dim> &obs) { obs_ = obs; }
///Set dimension of bounding box
void set_local_bbox(const Vecf<Dim>& bbox) { local_bbox_ = bbox; }
///Get the path that is used for dilation
vec_Vecf<Dim> get_path() const { return path_; }
///Get the Safe Flight Corridor
vec_E<Polyhedron<Dim>> get_polyhedrons() const { return polyhedrons_; }
///Get the ellipsoids
vec_E<Ellipsoid<Dim>> get_ellipsoids() const { return ellipsoids_; }
///Get the constraints of SFC as \f$Ax\leq b \f$
vec_E<LinearConstraint<Dim>> get_constraints() const {
vec_E<LinearConstraint<Dim>> constraints;
constraints.resize(polyhedrons_.size());
for (unsigned int i = 0; i < polyhedrons_.size(); i++){
const Vecf<Dim> pt = (path_[i] + path_[i+1])/2;
constraints[i] = LinearConstraint<Dim>(pt, polyhedrons_[i].hyperplanes());
}
return constraints;
}
/**
* @brief Decomposition thread
* @param path The path to dilate
* @param offset_x offset added to the long semi-axis, default is 0
*/
void dilate(const vec_Vecf<Dim> &path, double offset_x = 0) {
const unsigned int N = path.size() - 1;
lines_.resize(N);
ellipsoids_.resize(N);
polyhedrons_.resize(N);
for (unsigned int i = 0; i < N; i++) {
lines_[i] = std::make_shared<LineSegment<Dim>>(path[i], path[i+1]);
lines_[i]->set_local_bbox(local_bbox_);
lines_[i]->set_obs(obs_);
lines_[i]->dilate(offset_x);
ellipsoids_[i] = lines_[i]->get_ellipsoid();
polyhedrons_[i] = lines_[i]->get_polyhedron();
}
path_ = path;
if(global_bbox_min_.norm() != 0 || global_bbox_max_.norm() != 0) {
for(auto& it: polyhedrons_)
add_global_bbox(it);
}
}
protected:
template<int U = Dim>
typename std::enable_if<U == 2>::type
add_global_bbox(Polyhedron<Dim> &Vs) {
//**** add bound along X, Y axis
//*** X
Vs.add(Hyperplane2D(Vec2f(global_bbox_max_(0), 0), Vec2f(1, 0)));
Vs.add(Hyperplane2D(Vec2f(global_bbox_min_(0), 0), Vec2f(-1, 0)));
//*** Y
Vs.add(Hyperplane2D(Vec2f(0, global_bbox_max_(1)), Vec2f(0, 1)));
Vs.add(Hyperplane2D(Vec2f(0, global_bbox_min_(1)), Vec2f(0, -1)));
}
template<int U = Dim>
typename std::enable_if<U == 3>::type
add_global_bbox(Polyhedron<Dim> &Vs) {
//**** add bound along X, Y, Z axis
//*** Z
Vs.add(Hyperplane3D(Vec3f(0, 0, global_bbox_max_(2)), Vec3f(0, 0, 1)));
Vs.add(Hyperplane3D(Vec3f(0, 0, global_bbox_min_(2)), Vec3f(0, 0, -1)));
//*** X
Vs.add(Hyperplane3D(Vec3f(global_bbox_max_(0), 0, 0), Vec3f(1, 0, 0)));
Vs.add(Hyperplane3D(Vec3f(global_bbox_min_(0), 0, 0), Vec3f(-1, 0, 0)));
//*** Y
Vs.add(Hyperplane3D(Vec3f(0, global_bbox_max_(1), 0), Vec3f(0, 1, 0)));
Vs.add(Hyperplane3D(Vec3f(0, global_bbox_max_(1), 0), Vec3f(0, -1, 0)));
}
vec_Vecf<Dim> path_;
vec_Vecf<Dim> obs_;
vec_E<Ellipsoid<Dim>> ellipsoids_;
vec_E<Polyhedron<Dim>> polyhedrons_;
std::vector<std::shared_ptr<LineSegment<Dim>>> lines_;
Vecf<Dim> local_bbox_{Vecf<Dim>::Zero()};
Vecf<Dim> global_bbox_min_{Vecf<Dim>::Zero()}; // bounding box params
Vecf<Dim> global_bbox_max_{Vecf<Dim>::Zero()};
};
typedef EllipsoidDecomp<2> EllipsoidDecomp2D;
typedef EllipsoidDecomp<3> EllipsoidDecomp3D;
#endif

View File

@@ -0,0 +1,105 @@
/**
* @file iterative_decomp.h
* @brief IterativeDecomp Class
*/
#ifndef ITERATIVE_DECOMP_H
#define ITERATIVE_DECOMP_H
#include <decomp_util/ellipsoid_decomp.h>
/**
* @brief IterativeDecomp Class
*
* Iteratively calls ElliseDecomp to form a safer Safe Flight Corridor that is away from obstacles
*/
template <int Dim>
class IterativeDecomp : public EllipsoidDecomp<Dim>
{
public:
///Simple constructor
IterativeDecomp() {}
/**
* @brief Basic constructor
* @param origin The origin of the global bounding box
* @param dim The dimension of the global bounding box
*/
IterativeDecomp(const Vecf<Dim> &origin, const Vecf<Dim> &dim) :
EllipsoidDecomp<Dim>(origin, dim) {}
/**
* @brief Decomposition thread
* @param path_raw The path to dilate
* @param iter_num Max iteration number
* @param offset_x offset added to the long semi-axis, default is 0
* @param res Resolution to downsample the path
*/
void dilate_iter(const vec_Vecf<Dim> &path_raw, int iter_num = 5,
decimal_t res = 0, decimal_t offset_x = 0) {
vec_Vecf<Dim> path = res > 0 ? downsample(path_raw, res) : path_raw;
this->dilate(path, offset_x);
vec_Vecf<Dim> new_path = simplify(path);
for (int i = 0; i < iter_num; i++) {
if (new_path.size() == path.size())
break;
else {
path = new_path;
this->dilate(path, offset_x);
new_path = simplify(path);
}
}
}
protected:
/// Uniformly sample path into many segments
vec_Vecf<Dim> downsample(const vec_Vecf<Dim> &ps, decimal_t d) {
// subdivide according to length
if (ps.size() < 2)
return ps;
vec_Vecf<Dim> path;
for (unsigned int i = 1; i < ps.size(); i++) {
decimal_t dist = (ps[i] - ps[i - 1]).norm();
int cnt = std::ceil(dist / d);
for (int j = 0; j < cnt; j++)
path.push_back(ps[i - 1] + j * (ps[i] - ps[i - 1]) / cnt);
}
path.push_back(ps.back());
return path;
}
/// Get closest distance
decimal_t cal_closest_dist(const Vecf<Dim>& pt, const Polyhedron<Dim>& vs){
decimal_t dist = std::numeric_limits<decimal_t>::infinity();
for(const auto& it: vs.hyperplanes()){
decimal_t d = std::abs(it.n_.dot(pt - it.p_));
if(d < dist)
dist = d;
}
return dist;
}
/// Remove redundant waypoints
vec_Vecf<Dim> simplify(const vec_Vecf<Dim>& path) {
if(path.size() <= 2)
return path;
Vecf<Dim> ref_pt = path.front();
vec_Vecf<Dim> new_path;
new_path.push_back(ref_pt);
for(size_t i = 2; i < path.size(); i ++){
if(this->polyhedrons_[i-1].inside(ref_pt) &&
cal_closest_dist(ref_pt, this->polyhedrons_[i-1]) > 0.1) {
}
else{
ref_pt = path[i-1];
new_path.push_back(ref_pt);
}
}
new_path.push_back(path.back());
return new_path;
}
};
typedef IterativeDecomp<2> IterativeDecomp2D;
typedef IterativeDecomp<3> IterativeDecomp3D;
#endif

View File

@@ -0,0 +1,222 @@
/**
* @file line_segment.h
* @brief LineSegment Class
*/
#ifndef LINE_SEGMENT_H
#define LINE_SEGMENT_H
#include <decomp_util/decomp_base.h>
#include <decomp_geometry/geometric_utils.h>
/**
* @brief Line Segment Class
*
* The basic element in EllipsoidDecomp
*/
template <int Dim>
class LineSegment : public DecompBase<Dim> {
public:
///Simple constructor
LineSegment() {};
/**
* @brief Basic constructor
* @param p1 One end of the line seg
* @param p2 The other end of the line seg
*/
LineSegment(const Vecf<Dim> &p1, const Vecf<Dim> &p2) : p1_(p1), p2_(p2) {}
/**
* @brief Infalte the line segment
* @param radius the offset added to the long semi-axis
*/
void dilate(decimal_t radius) {
find_ellipsoid(radius);
this->find_polyhedron();
add_local_bbox(this->polyhedron_);
}
/// Get the line
vec_Vecf<Dim> get_line_segment() const {
vec_Vecf<Dim> line;
line.push_back(p1_);
line.push_back(p2_);
return line;
}
protected:
///Add the bounding box
void add_local_bbox(Polyhedron<Dim> &Vs) {
if(this->local_bbox_.norm() == 0)
return;
//**** virtual walls parallel to path p1->p2
Vecf<Dim> dir = (p2_ - p1_).normalized();
Vecf<Dim> dir_h = Vecf<Dim>::Zero();
dir_h(0) = dir(1), dir_h(1) = -dir(0);
if (dir_h.norm() == 0) {
if(Dim == 2)
dir_h << -1, 0;
else
dir_h << -1, 0, 0;
}
dir_h = dir_h.normalized();
// along x
Vecf<Dim> pp1 = p1_ + dir_h * this->local_bbox_(1);
Vecf<Dim> pp2 = p1_ - dir_h * this->local_bbox_(1);
Vs.add(Hyperplane<Dim>(pp1, dir_h));
Vs.add(Hyperplane<Dim>(pp2, -dir_h));
// along y
Vecf<Dim> pp3 = p2_ + dir * this->local_bbox_(0);
Vecf<Dim> pp4 = p1_ - dir * this->local_bbox_(0);
Vs.add(Hyperplane<Dim>(pp3, dir));
Vs.add(Hyperplane<Dim>(pp4, -dir));
// along z
if(Dim > 2) {
Vecf<Dim> dir_v;
dir_v(0) = dir(1) * dir_h(2) - dir(2) * dir_h(1);
dir_v(1) = dir(2) * dir_h(0) - dir(0) * dir_h(2);
dir_v(2) = dir(0) * dir_h(1) - dir(1) * dir_h(0);
Vecf<Dim> pp5 = p1_ + dir_v * this->local_bbox_(2);
Vecf<Dim> pp6 = p1_ - dir_v * this->local_bbox_(2);
Vs.add(Hyperplane<Dim>(pp5, dir_v));
Vs.add(Hyperplane<Dim>(pp6, -dir_v));
}
}
/// Find ellipsoid in 2D
template<int U = Dim>
typename std::enable_if<U == 2>::type
find_ellipsoid(double offset_x) {
const decimal_t f = (p1_ - p2_).norm() / 2;
Matf<Dim, Dim> C = f * Matf<Dim, Dim>::Identity();
Vecf<Dim> axes = Vecf<Dim>::Constant(f);
C(0, 0) += offset_x;
axes(0) += offset_x;
if(axes(0) > 0) {
double ratio = axes(1) / axes(0);
axes *= ratio;
C *= ratio;
}
const auto Ri = vec2_to_rotation(p2_ - p1_);
C = Ri * C * Ri.transpose();
Ellipsoid<Dim> E(C, (p1_ + p2_) / 2);
auto obs = E.points_inside(this->obs_);
auto obs_inside = obs;
//**** decide short axes
while (!obs_inside.empty()) {
const auto pw = E.closest_point(obs_inside);
Vecf<Dim> p = Ri.transpose() * (pw - E.d()); // to ellipsoid frame
if(p(0) < axes(0))
axes(1) = std::abs(p(1)) / std::sqrt(1 - std::pow(p(0) / axes(0), 2));
Matf<Dim, Dim> new_C = Matf<Dim, Dim>::Identity();
new_C(0, 0) = axes(0);
new_C(1, 1) = axes(1);
E.C_ = Ri * new_C * Ri.transpose();
vec_Vecf<Dim> obs_new;
for(const auto &it: obs_inside) {
if(1 - E.dist(it) > epsilon_)
obs_new.push_back(it);
}
obs_inside = obs_new;
}
this->ellipsoid_ = E;
}
/// Find ellipsoid in 3D
template<int U = Dim>
typename std::enable_if<U == 3>::type
find_ellipsoid(double offset_x) {
const decimal_t f = (p1_ - p2_).norm() / 2;
Matf<Dim, Dim> C = f * Matf<Dim, Dim>::Identity();
Vecf<Dim> axes = Vecf<Dim>::Constant(f);
C(0, 0) += offset_x;
axes(0) += offset_x;
if(axes(0) > 0) {
double ratio = axes(1) / axes(0);
axes *= ratio;
C *= ratio;
}
const auto Ri = vec3_to_rotation(p2_ - p1_);
C = Ri * C * Ri.transpose();
Ellipsoid<Dim> E(C, (p1_ + p2_) / 2);
auto Rf = Ri;
auto obs = E.points_inside(this->obs_);
auto obs_inside = obs;
//**** decide short axes
while (!obs_inside.empty()) {
const auto pw = E.closest_point(obs_inside);
Vecf<Dim> p = Ri.transpose() * (pw - E.d()); // to ellipsoid frame
const decimal_t roll = atan2(p(2), p(1));
Rf = Ri * Quatf(cos(roll / 2), sin(roll / 2), 0, 0);
p = Rf.transpose() * (pw - E.d());
if(p(0) < axes(0))
axes(1) = std::abs(p(1)) / std::sqrt(1 - std::pow(p(0) / axes(0), 2));
Matf<Dim, Dim> new_C = Matf<Dim, Dim>::Identity();
new_C(0, 0) = axes(0);
new_C(1, 1) = axes(1);
new_C(2, 2) = axes(1);
E.C_ = Rf * new_C * Rf.transpose();
vec_Vecf<Dim> obs_new;
for(const auto &it: obs_inside) {
if(1 - E.dist(it) > epsilon_)
obs_new.push_back(it);
}
obs_inside = obs_new;
}
//**** reset ellipsoid with old axes(2)
C = f * Matf<Dim, Dim>::Identity();
C(0, 0) = axes(0);
C(1, 1) = axes(1);
C(2, 2) = axes(2);
E.C_ = Rf * C * Rf.transpose();
obs_inside = E.points_inside(obs);
while (!obs_inside.empty()) {
const auto pw = E.closest_point(obs_inside);
Vec3f p = Rf.transpose() * (pw - E.d());
decimal_t dd = 1 - std::pow(p(0) / axes(0), 2) -
std::pow(p(1) / axes(1), 2);
if(dd > epsilon_)
axes(2) = std::abs(p(2)) / std::sqrt(dd);
Matf<Dim, Dim> new_C = Matf<Dim, Dim>::Identity();
new_C(0, 0) = axes(0);
new_C(1, 1) = axes(1);
new_C(2, 2) = axes(2);
E.C_ = Rf * new_C * Rf.transpose();
vec_Vecf<Dim> obs_new;
for(const auto &it: obs_inside) {
if(1 - E.dist(it) > epsilon_)
obs_new.push_back(it);
}
obs_inside = obs_new;
}
this->ellipsoid_ = E;
}
/// One end of line segment, input
Vecf<Dim> p1_;
/// The other end of line segment, input
Vecf<Dim> p2_;
};
typedef LineSegment<2> LineSegment2D;
typedef LineSegment<3> LineSegment3D;
#endif

View File

@@ -0,0 +1,80 @@
/**
* @file seed_decomp.h
* @brief SeedDecomp Class
*/
#ifndef SEED_DECOMP_H
#define SEED_DECOMP_H
#include <decomp_util/decomp_base.h>
/**
* @brief Seed Decomp Class
*
* Dilate around the given point
*/
template <int Dim>
class SeedDecomp : public DecompBase<Dim> {
public:
///Simple constructor
SeedDecomp() {};
/**
* @brief Basic constructor
* @param p1 One end of the line seg
* @param p2 The other end of the line seg
*/
SeedDecomp(const Vecf<Dim> &p) : p_(p) {}
/**
* @brief Inflate the seed with a sphere
* @param radius Robot radius
*/
void dilate(decimal_t radius) {
this->ellipsoid_ = Ellipsoid<Dim>(radius * Matf<Dim, Dim>::Identity(), p_);
this->find_polyhedron();
add_local_bbox(this->polyhedron_);
}
/// Get the center
Vecf<Dim> get_seed() const {
return p_;
}
protected:
///Add the bounding box
void add_local_bbox(Polyhedron<Dim> &Vs) {
if(this->local_bbox_.norm() == 0)
return;
//**** virtual walls x-y-z
Vecf<Dim> dir = Vecf<Dim>::UnitX();
Vecf<Dim> dir_h = Vecf<Dim>::UnitY();
Vecf<Dim> pp1 = p_ + dir_h * this->local_bbox_(1);
Vecf<Dim> pp2 = p_ - dir_h * this->local_bbox_(1);
Vs.add(Hyperplane<Dim>(pp1, dir_h));
Vs.add(Hyperplane<Dim>(pp2, -dir_h));
// along y
Vecf<Dim> pp3 = p_ + dir * this->local_bbox_(0);
Vecf<Dim> pp4 = p_ - dir * this->local_bbox_(0);
Vs.add(Hyperplane<Dim>(pp3, dir));
Vs.add(Hyperplane<Dim>(pp4, -dir));
// along z
if(Dim > 2) {
Vecf<Dim> dir_v = Vecf<Dim>::UnitZ();
Vecf<Dim> pp5 = p_ + dir_v * this->local_bbox_(2);
Vecf<Dim> pp6 = p_ - dir_v * this->local_bbox_(2);
Vs.add(Hyperplane<Dim>(pp5, dir_v));
Vs.add(Hyperplane<Dim>(pp6, -dir_v));
}
}
///Seed location
Vecf<Dim> p_;
};
typedef SeedDecomp<2> SeedDecomp2D;
typedef SeedDecomp<3> SeedDecomp3D;
#endif

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<package format="2">
<name>decomp_ros_utils</name>
<version>0.0.0</version>
<description>The decomp_ros_utils package</description>
<maintainer email="sikang@todo.todo">sikang</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>catkin_simple</build_depend>
<depend>roscpp</depend>
<depend>rviz</depend>
<depend>decomp_ros_msgs</depend>
<export>
<rviz plugin="${prefix}/plugin_description.xml"/>
</export>
</package>

View File

@@ -0,0 +1,18 @@
<library path="lib/libdecomp_rviz_plugins">
<class name="decomp_rviz_plugins/EllipsoidArray"
type="decomp_rviz_plugins::EllipsoidArrayDisplay"
base_class_type="rviz::Display">
<description>
visualize decomp_ros_msgs/EllipsoidArray msg.
</description>
</class>
<class name="decomp_rviz_plugins/PolyhedronArray"
type="decomp_rviz_plugins::PolyhedronArrayDisplay"
base_class_type="rviz::Display">
<description>
visualize decomp_ros_msgs/PolyhedronArray msg.
</description>
</class>
</library>

View File

@@ -0,0 +1,56 @@
#include "bound_visual.h"
namespace decomp_rviz_plugins {
BoundVisual::BoundVisual(Ogre::SceneManager *scene_manager,
Ogre::SceneNode *parent_node) {
scene_manager_ = scene_manager;
frame_node_ = parent_node->createChildSceneNode();
}
BoundVisual::~BoundVisual() { scene_manager_->destroySceneNode(frame_node_); }
void BoundVisual::setMessage(const vec_E<vec_Vec3f>& bds) {
objs_.clear();
if (bds.empty())
return;
size_t num_faces = bds.size();
objs_.resize(num_faces);
for (auto &it : objs_)
it.reset(new rviz::BillboardLine(scene_manager_, frame_node_));
int cnt = 0;
for (const auto &vs : bds) {
for (unsigned int i = 0; i <= vs.size(); i++) {
if (i < vs.size()) {
if(!std::isnan(vs[i](0)))
objs_[cnt]->addPoint(Ogre::Vector3(vs[i](0), vs[i](1), vs[i](2)));
}
else {
if(!std::isnan(vs[0](0)))
objs_[cnt]->addPoint(Ogre::Vector3(vs[0](0), vs[0](1), vs[0](2)));
}
}
cnt++;
}
}
void BoundVisual::setFramePosition(const Ogre::Vector3 &position) {
frame_node_->setPosition(position);
}
void BoundVisual::setFrameOrientation(const Ogre::Quaternion &orientation) {
frame_node_->setOrientation(orientation);
}
void BoundVisual::setColor(float r, float g, float b, float a) {
for (auto &it : objs_)
it->setColor(r, g, b, a);
}
void BoundVisual::setScale(float s) {
for (auto &it : objs_)
it->setLineWidth(s);
}
}

View File

@@ -0,0 +1,35 @@
#ifndef BOUND_VISUAL_H
#define BOUND_VISUAL_H
#include <decomp_basis/data_type.h>
#include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/ogre_helpers/billboard_line.h>
namespace decomp_rviz_plugins {
class BoundVisual {
public:
BoundVisual(Ogre::SceneManager *scene_manager, Ogre::SceneNode *parent_node);
~BoundVisual();
void setMessage(const vec_E<vec_Vec3f> &bds);
void setFramePosition(const Ogre::Vector3 &position);
void setFrameOrientation(const Ogre::Quaternion &orientation);
void setColor(float r, float g, float b, float a);
void setScale(float s);
private:
std::vector<std::unique_ptr<rviz::BillboardLine>> objs_;
Ogre::SceneNode *frame_node_;
Ogre::SceneManager *scene_manager_;
};
}
#endif

View File

@@ -0,0 +1,62 @@
#include <tf/transform_listener.h>
#include "ellipsoid_array_display.h"
namespace decomp_rviz_plugins {
EllipsoidArrayDisplay::EllipsoidArrayDisplay() {
color_property_ = new rviz::ColorProperty("Color", QColor(204, 51, 204),
"Color of ellipsoids.",
this, SLOT(updateColorAndAlpha()));
alpha_property_ = new rviz::FloatProperty(
"Alpha", 0.5, "0 is fully transparent, 1.0 is fully opaque.", this,
SLOT(updateColorAndAlpha()));
}
void EllipsoidArrayDisplay::onInitialize() {
MFDClass::onInitialize();
}
EllipsoidArrayDisplay::~EllipsoidArrayDisplay() {}
void EllipsoidArrayDisplay::reset() {
MFDClass::reset();
visual_ = nullptr;
}
void EllipsoidArrayDisplay::updateColorAndAlpha() {
float alpha = alpha_property_->getFloat();
Ogre::ColourValue color = color_property_->getOgreColor();
if (visual_)
visual_->setColor(color.r, color.g, color.b, alpha);
}
void EllipsoidArrayDisplay::processMessage(const decomp_ros_msgs::EllipsoidArray::ConstPtr &msg) {
Ogre::Quaternion orientation;
Ogre::Vector3 position;
if (!context_->getFrameManager()->getTransform(
msg->header.frame_id, msg->header.stamp, position, orientation)) {
ROS_DEBUG("Error transforming from frame '%s' to frame '%s'",
msg->header.frame_id.c_str(), qPrintable(fixed_frame_));
return;
}
std::shared_ptr<EllipsoidArrayVisual> visual;
visual.reset(new EllipsoidArrayVisual(context_->getSceneManager(), scene_node_));
visual->setMessage(msg);
visual->setFramePosition(position);
visual->setFrameOrientation(orientation);
float alpha = alpha_property_->getFloat();
Ogre::ColourValue color = color_property_->getOgreColor();
visual->setColor(color.r, color.g, color.b, alpha);
visual_ = visual;
}
}
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(decomp_rviz_plugins::EllipsoidArrayDisplay, rviz::Display)

View File

@@ -0,0 +1,41 @@
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/visualization_manager.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/frame_manager.h>
#include <rviz/load_resource.h>
#include <decomp_ros_msgs/EllipsoidArray.h>
#include <rviz/message_filter_display.h>
#include "ellipsoid_array_visual.h"
namespace decomp_rviz_plugins {
class EllipsoidArrayVisual;
class EllipsoidArrayDisplay
: public rviz::MessageFilterDisplay<decomp_ros_msgs::EllipsoidArray> {
Q_OBJECT
public:
EllipsoidArrayDisplay();
~EllipsoidArrayDisplay();
protected:
void onInitialize();
void reset();
private Q_SLOTS:
void updateColorAndAlpha();
private:
void processMessage(const decomp_ros_msgs::EllipsoidArray::ConstPtr &msg);
std::shared_ptr<EllipsoidArrayVisual> visual_;
rviz::ColorProperty *color_property_;
rviz::FloatProperty *alpha_property_;
};
}

View File

@@ -0,0 +1,72 @@
#include "ellipsoid_array_visual.h"
namespace decomp_rviz_plugins {
EllipsoidArrayVisual::EllipsoidArrayVisual(Ogre::SceneManager *scene_manager,
Ogre::SceneNode *parent_node) {
scene_manager_ = scene_manager;
frame_node_ = parent_node->createChildSceneNode();
}
EllipsoidArrayVisual::~EllipsoidArrayVisual() {
scene_manager_->destroySceneNode(frame_node_);
}
void EllipsoidArrayVisual::setMessage(const decomp_ros_msgs::EllipsoidArray::ConstPtr &msg) {
objs_.clear();
if (msg->ellipsoids.empty())
return;
for (const auto& it: msg->ellipsoids) {
if(std::isnan(it.d[0]) ||
std::isnan(it.d[1]) ||
std::isnan(it.d[2]))
return;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if(std::isnan(it.E[3 * i + j]))
return;
}
objs_.resize(msg->ellipsoids.size());
for (auto &it : objs_)
it.reset(new rviz::Shape(rviz::Shape::Type::Sphere, scene_manager_,
frame_node_));
int cnt = 0;
for (const auto &it : msg->ellipsoids) {
Mat3f E;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
E(i, j) = it.E[3 * i + j];
Eigen::SelfAdjointEigenSolver<Mat3f> es(E);
Ogre::Vector3 scale(2 * es.eigenvalues()[0], 2 * es.eigenvalues()[1],
2 * es.eigenvalues()[2]);
objs_[cnt]->setScale(scale);
Ogre::Vector3 d(it.d[0], it.d[1], it.d[2]);
objs_[cnt]->setPosition(d);
Quatf q(es.eigenvectors().determinant() * es.eigenvectors());
Ogre::Quaternion o(q.w(), q.x(), q.y(), q.z());
objs_[cnt]->setOrientation(o);
cnt++;
}
}
void EllipsoidArrayVisual::setFramePosition(const Ogre::Vector3 &position) {
frame_node_->setPosition(position);
}
void EllipsoidArrayVisual::setFrameOrientation(
const Ogre::Quaternion &orientation) {
frame_node_->setOrientation(orientation);
}
void EllipsoidArrayVisual::setColor(float r, float g, float b, float a) {
for (auto &it : objs_)
it->setColor(r, g, b, a);
}
}

View File

@@ -0,0 +1,37 @@
#ifndef ELLIPSOIDS_VISUAL_H
#define ELLIPSOIDS_VISUAL_H
#include <decomp_ros_msgs/EllipsoidArray.h>
#include <decomp_geometry/ellipsoid.h>
#include <Eigen/Eigenvalues>
#include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/ogre_helpers/shape.h>
namespace decomp_rviz_plugins {
class EllipsoidArrayVisual {
public:
EllipsoidArrayVisual(Ogre::SceneManager *scene_manager,
Ogre::SceneNode *parent_node);
virtual ~EllipsoidArrayVisual();
void setMessage(const decomp_ros_msgs::EllipsoidArray::ConstPtr &msg);
void setFramePosition(const Ogre::Vector3 &position);
void setFrameOrientation(const Ogre::Quaternion &orientation);
void setColor(float r, float g, float b, float a);
private:
std::vector<std::unique_ptr<rviz::Shape>> objs_;
Ogre::SceneNode *frame_node_;
Ogre::SceneManager *scene_manager_;
};
}
#endif

View File

@@ -0,0 +1,56 @@
#include "mesh_visual.h"
namespace decomp_rviz_plugins {
MeshVisual::MeshVisual(Ogre::SceneManager *scene_manager,
Ogre::SceneNode *parent_node) {
scene_manager_ = scene_manager;
frame_node_ = parent_node->createChildSceneNode();
obj_.reset(new rviz::MeshShape(scene_manager_, frame_node_));
}
MeshVisual::~MeshVisual() { scene_manager_->destroySceneNode(frame_node_); }
void MeshVisual::setMessage(const vec_E<vec_Vec3f> &bds) {
obj_->clear();
if (bds.empty())
return;
obj_->beginTriangles();
int free_cnt = 0;
for (const auto &vs: bds) {
if (vs.size() > 2) {
Vec3f p0 = vs[0];
Vec3f p1 = vs[1];
Vec3f p2 = vs[2];
Vec3f n = (p2-p0).cross(p1-p0);
n = n.normalized();
if(std::isnan(n(0)))
n = Vec3f(0, 0, -1);
int ref_cnt = free_cnt;
Ogre::Vector3 normal(n(0), n(1), n(2));
for (unsigned int i = 0; i < vs.size(); i++) {
obj_->addVertex(Ogre::Vector3(vs[i](0), vs[i](1), vs[i](2)), normal);
if (i > 1 && i < vs.size())
obj_->addTriangle(ref_cnt, free_cnt - 1, free_cnt);
free_cnt++;
}
}
}
obj_->endTriangles();
}
// Position and orientation are passed through to the SceneNode.
void MeshVisual::setFramePosition(const Ogre::Vector3 &position) {
frame_node_->setPosition(position);
}
void MeshVisual::setFrameOrientation(const Ogre::Quaternion &orientation) {
frame_node_->setOrientation(orientation);
}
void MeshVisual::setColor(float r, float g, float b, float a) {
obj_->setColor(r, g, b, a);
}
}

View File

@@ -0,0 +1,35 @@
#ifndef MESH_VISUAL_H
#define MESH_VISUAL_H
#include <decomp_geometry/polyhedron.h>
#include <Eigen/Eigenvalues>
#include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/ogre_helpers/mesh_shape.h>
namespace decomp_rviz_plugins {
class MeshVisual {
public:
MeshVisual(Ogre::SceneManager *scene_manager, Ogre::SceneNode *parent_node);
virtual ~MeshVisual();
void setMessage(const vec_E<vec_Vec3f> &bds);
void setFramePosition(const Ogre::Vector3 &position);
void setFrameOrientation(const Ogre::Quaternion &orientation);
void setColor(float r, float g, float b, float a);
private:
std::unique_ptr<rviz::MeshShape> obj_;
Ogre::SceneNode *frame_node_;
Ogre::SceneManager *scene_manager_;
};
}
#endif

View File

@@ -0,0 +1,186 @@
#include "polyhedron_array_display.h"
namespace decomp_rviz_plugins {
PolyhedronArrayDisplay::PolyhedronArrayDisplay() {
mesh_color_property_ =
new rviz::ColorProperty("MeshColor", QColor(0, 170, 255), "Mesh color.",
this, SLOT(updateMeshColorAndAlpha()));
bound_color_property_ =
new rviz::ColorProperty("BoundColor", QColor(255, 0, 0), "Bound color.",
this, SLOT(updateBoundColorAndAlpha()));
alpha_property_ = new rviz::FloatProperty(
"Alpha", 0.2,
"0 is fully transparent, 1.0 is fully opaque, only affect mesh", this,
SLOT(updateMeshColorAndAlpha()));
scale_property_ = new rviz::FloatProperty("Scale", 0.1, "bound scale.", this,
SLOT(updateScale()));
vs_scale_property_ = new rviz::FloatProperty("VsScale", 1.0, "Vs scale.", this,
SLOT(updateVsScale()));
vs_color_property_ =
new rviz::ColorProperty("VsColor", QColor(0, 255, 0), "Vs color.",
this, SLOT(updateVsColorAndAlpha()));
state_property_ = new rviz::EnumProperty(
"State", "Mesh", "A Polygon can be represented as two states: Mesh and "
"Bound, this option allows selecting visualizing Polygon"
"in corresponding state",
this, SLOT(updateState()));
state_property_->addOption("Mesh", 0);
state_property_->addOption("Bound", 1);
state_property_->addOption("Both", 2);
state_property_->addOption("Vs", 3);
}
void PolyhedronArrayDisplay::onInitialize() { MFDClass::onInitialize(); }
PolyhedronArrayDisplay::~PolyhedronArrayDisplay() {}
void PolyhedronArrayDisplay::reset() {
MFDClass::reset();
visual_mesh_ = nullptr;
visual_bound_ = nullptr;
visual_vector_ = nullptr;
}
void PolyhedronArrayDisplay::processMessage(const decomp_ros_msgs::PolyhedronArray::ConstPtr &msg) {
if (!context_->getFrameManager()->getTransform(
msg->header.frame_id, msg->header.stamp, position_, orientation_)) {
ROS_DEBUG("Error transforming from frame '%s' to frame '%s'",
msg->header.frame_id.c_str(), qPrintable(fixed_frame_));
return;
}
vertices_.clear();
vs_.clear();
const auto polys = DecompROS::ros_to_polyhedron_array(*msg);
for(const auto& polyhedron: polys){
vec_E<vec_Vec3f> bds = cal_vertices(polyhedron);
vertices_.insert(vertices_.end(), bds.begin(), bds.end());
const auto vs = polyhedron.cal_normals();
vs_.insert(vs_.end(), vs.begin(), vs.end());
}
int state = state_property_->getOptionInt();
visualizeMessage(state);
}
void PolyhedronArrayDisplay::visualizeMesh() {
std::shared_ptr<MeshVisual> visual_mesh;
visual_mesh.reset(new MeshVisual(context_->getSceneManager(), scene_node_));
visual_mesh->setMessage(vertices_);
visual_mesh->setFramePosition(position_);
visual_mesh->setFrameOrientation(orientation_);
float alpha = alpha_property_->getFloat();
Ogre::ColourValue color = mesh_color_property_->getOgreColor();
visual_mesh->setColor(color.r, color.g, color.b, alpha);
visual_mesh_ = visual_mesh;
}
void PolyhedronArrayDisplay::visualizeBound() {
std::shared_ptr<BoundVisual> visual_bound;
visual_bound.reset(new BoundVisual(context_->getSceneManager(), scene_node_));
visual_bound->setMessage(vertices_);
visual_bound->setFramePosition(position_);
visual_bound->setFrameOrientation(orientation_);
Ogre::ColourValue color = bound_color_property_->getOgreColor();
visual_bound->setColor(color.r, color.g, color.b, 1.0);
float scale = scale_property_->getFloat();
visual_bound->setScale(scale);
visual_bound_ = visual_bound;
}
void PolyhedronArrayDisplay::visualizeVs() {
std::shared_ptr<VectorVisual> visual_vector;
visual_vector.reset(new VectorVisual(context_->getSceneManager(), scene_node_));
visual_vector->setMessage(vs_);
visual_vector->setFramePosition(position_);
visual_vector->setFrameOrientation(orientation_);
Ogre::ColourValue color = vs_color_property_->getOgreColor();
visual_vector->setColor(color.r, color.g, color.b, 1.0);
visual_vector_ = visual_vector;
}
void PolyhedronArrayDisplay::visualizeMessage(int state) {
switch (state) {
case 0:
visual_bound_ = nullptr;
visual_vector_ = nullptr;
visualizeMesh();
break;
case 1:
visual_mesh_ = nullptr;
visual_vector_ = nullptr;
visualizeBound();
break;
case 2:
visual_vector_ = nullptr;
visualizeMesh();
visualizeBound();
break;
case 3:
visualizeVs();
break;
default:
std::cout << "Invalid State: " << state << std::endl;
}
}
void PolyhedronArrayDisplay::updateMeshColorAndAlpha() {
float alpha = alpha_property_->getFloat();
Ogre::ColourValue color = mesh_color_property_->getOgreColor();
if(visual_mesh_)
visual_mesh_->setColor(color.r, color.g, color.b, alpha);
}
void PolyhedronArrayDisplay::updateBoundColorAndAlpha() {
Ogre::ColourValue color = bound_color_property_->getOgreColor();
if(visual_bound_)
visual_bound_->setColor(color.r, color.g, color.b, 1.0);
}
void PolyhedronArrayDisplay::updateState() {
int state = state_property_->getOptionInt();
visualizeMessage(state);
}
void PolyhedronArrayDisplay::updateScale() {
float s = scale_property_->getFloat();
if(visual_bound_)
visual_bound_->setScale(s);
}
void PolyhedronArrayDisplay::updateVsScale() {
float s = vs_scale_property_->getFloat();
if(visual_vector_)
visual_vector_->setScale(s);
}
void PolyhedronArrayDisplay::updateVsColorAndAlpha() {
Ogre::ColourValue color = vs_color_property_->getOgreColor();
if(visual_vector_)
visual_vector_->setColor(color.r, color.g, color.b, 1);
}
}
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(decomp_rviz_plugins::PolyhedronArrayDisplay, rviz::Display)

View File

@@ -0,0 +1,68 @@
#include <decomp_ros_msgs/PolyhedronArray.h>
#include <rviz/message_filter_display.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/int_property.h>
#include <rviz/properties/enum_property.h>
#include <rviz/visualization_manager.h>
#include <rviz/frame_manager.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/load_resource.h>
#include "mesh_visual.h"
#include "bound_visual.h"
#include "vector_visual.h"
#include <decomp_ros_utils/data_ros_utils.h>
#include <decomp_geometry/geometric_utils.h>
namespace decomp_rviz_plugins {
class PolyhedronArrayDisplay
: public rviz::MessageFilterDisplay<decomp_ros_msgs::PolyhedronArray> {
Q_OBJECT
public:
PolyhedronArrayDisplay();
virtual ~PolyhedronArrayDisplay();
protected:
virtual void onInitialize();
virtual void reset();
private Q_SLOTS:
void updateMeshColorAndAlpha();
void updateBoundColorAndAlpha();
void updateVsColorAndAlpha();
void updateState();
void updateScale();
void updateVsScale();
private:
void processMessage(const decomp_ros_msgs::PolyhedronArray::ConstPtr &msg);
void visualizeMessage(int state);
void visualizeMesh();
void visualizeBound();
void visualizeVs();
std::shared_ptr<MeshVisual> visual_mesh_;
std::shared_ptr<BoundVisual> visual_bound_;
std::shared_ptr<VectorVisual> visual_vector_;
rviz::ColorProperty *mesh_color_property_;
rviz::ColorProperty *bound_color_property_;
rviz::ColorProperty *vs_color_property_;
rviz::FloatProperty *alpha_property_;
rviz::FloatProperty *scale_property_;
rviz::FloatProperty *vs_scale_property_;
rviz::EnumProperty *state_property_;
Ogre::Vector3 position_;
Ogre::Quaternion orientation_;
vec_E<vec_Vec3f> vertices_;
vec_E<std::pair<Vec3f, Vec3f>> vs_;
};
}

View File

@@ -0,0 +1,58 @@
#include "vector_visual.h"
namespace decomp_rviz_plugins {
VectorVisual::VectorVisual(Ogre::SceneManager *scene_manager,
Ogre::SceneNode *parent_node) {
scene_manager_ = scene_manager;
frame_node_ = parent_node->createChildSceneNode();
}
VectorVisual::~VectorVisual() { scene_manager_->destroySceneNode(frame_node_); }
void VectorVisual::setMessage(const vec_E<std::pair<Vec3f, Vec3f>> &vs) {
objs_.clear();
vs_ = vs;
if (vs.empty())
return;
objs_.resize(vs.size());
for (auto &it : objs_)
it.reset(new rviz::Arrow(scene_manager_, frame_node_));
int cnt = 0;
for (const auto &v : vs) {
Vec3f n = v.second.normalized();
objs_[cnt]->setDirection(Ogre::Vector3(n(0), n(1), n(2)));
objs_[cnt]->setPosition(Ogre::Vector3(v.first(0), v.first(1), v.first(2)));
objs_[cnt]->setScale(s_ * Ogre::Vector3(1.0, 1.0, 1.0));
float d = s_ * v.second.norm();
float shaft_length = 0.7 * d;
float head_length = 0.3 * d;
objs_[cnt]->set(shaft_length, d / 8, head_length, d / 5);
cnt ++;
}
}
void VectorVisual::setFramePosition(const Ogre::Vector3 &position) {
frame_node_->setPosition(position);
}
void VectorVisual::setFrameOrientation(const Ogre::Quaternion &orientation) {
frame_node_->setOrientation(orientation);
}
void VectorVisual::setColor(float r, float g, float b, float a) {
for (auto &it : objs_)
it->setColor(r, g, b, a);
}
void VectorVisual::setScale(float s) {
s_ = s;
for (unsigned int i = 0; i < objs_.size(); i++){
float d = s_ * vs_[i].second.norm();
float shaft_length = 0.7 * d;
float head_length = 0.3 * d;
objs_[i]->set(shaft_length, d / 8, head_length, d / 5);
}
}
}

View File

@@ -0,0 +1,35 @@
#ifndef VECTOR_VISUAL_H
#define VECTOR_VISUAL_H
#include <decomp_basis/data_type.h>
#include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <rviz/ogre_helpers/arrow.h>
namespace decomp_rviz_plugins {
class VectorVisual {
public:
VectorVisual(Ogre::SceneManager *scene_manager, Ogre::SceneNode *parent_node);
~VectorVisual();
void setMessage(const vec_E<std::pair<Vec3f, Vec3f>> &vs);
void setFramePosition(const Ogre::Vector3 &position);
void setFrameOrientation(const Ogre::Quaternion &orientation);
void setColor(float r, float g, float b, float a);
void setScale(float s);
private:
std::vector<std::unique_ptr<rviz::Arrow>> objs_;
Ogre::SceneNode *frame_node_;
Ogre::SceneManager *scene_manager_;
float s_ = 1.0;
vec_E<std::pair<Vec3f, Vec3f>> vs_;
};
}
#endif

View File

@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8.3)
project(catkin_simple)
find_package(catkin REQUIRED)
catkin_package(
CATKIN_DEPENDS catkin
CFG_EXTRAS catkin_simple-extras.cmake
)

View File

@@ -0,0 +1,226 @@
# Generated from: catkin_simple/cmake/catkin_simple-extras.cmake.em
if(_CATKIN_SIMPLE_EXTRAS_INCLUDED_)
return()
endif()
set(_CATKIN_SIMPLE_EXTRAS_INCLUDED_ TRUE)
include(CMakeParseArguments)
@[if DEVELSPACE]@
# cmake dir in develspace
set(catkin_simple_CMAKE_DIR "@(CMAKE_CURRENT_SOURCE_DIR)/cmake")
@[else]@
# cmake dir in installspace
set(catkin_simple_CMAKE_DIR "@(PKG_CMAKE_DIR)")
@[end if]@
macro(catkin_simple)
# Arguments
# ALL_DEPS_REQUIRED -- Add the "REQUIRED" flag when calling
# FIND_PACKAGE() for each dependency
cmake_parse_arguments(cs_args "ALL_DEPS_REQUIRED" "" "" ${ARGN})
if(TARGET ${PROJECT_NAME}_package)
message(WARNING "Could not create target '${${PROJECT_NAME}_package}' for project ${PROJECT_NAME}, as it already exists.")
endif()
add_custom_target(${PROJECT_NAME}_package)
set(${PROJECT_NAME}_TARGETS)
set(${PROJECT_NAME}_LIBRARIES)
find_package(catkin REQUIRED)
# call catkin_package_xml() if it has not been called before
if(NOT _CATKIN_CURRENT_PACKAGE)
catkin_package_xml()
endif()
set(${PROJECT_NAME}_CATKIN_BUILD_DEPENDS)
set(${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS)
foreach(dep ${${PROJECT_NAME}_BUILD_DEPENDS})
# If this flag is defined, add the "REQUIRED" flag
# to all FIND_PACKAGE calls
if(cs_args_ALL_DEPS_REQUIRED)
find_package(${dep} REQUIRED)
else()
find_package(${dep} QUIET)
endif()
if(${dep}_FOUND_CATKIN_PROJECT)
list(APPEND ${PROJECT_NAME}_CATKIN_BUILD_DEPENDS ${dep})
list(APPEND ${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS ${${dep}_EXPORTED_TARGETS})
endif()
endforeach()
# Let find_package(catkin ...) do the heavy lifting
find_package(catkin REQUIRED COMPONENTS ${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS})
# add include directory if available
set(${PROJECT_NAME}_LOCAL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(NOT IS_DIRECTORY ${${PROJECT_NAME}_LOCAL_INCLUDE_DIR})
set(${PROJECT_NAME}_LOCAL_INCLUDE_DIR)
endif()
include_directories(${${PROJECT_NAME}_LOCAL_INCLUDE_DIR} ${catkin_INCLUDE_DIRS})
# perform action/msg/srv generation if necessary
if(message_generation_FOUND_CATKIN_PROJECT)
set(${PROJECT_NAME}_DO_MESSAGE_GENERATION FALSE)
# add action files if available
set(${PROJECT_NAME}_LOCAL_ACTION_DIR ${CMAKE_CURRENT_SOURCE_DIR}/action)
if(NOT IS_DIRECTORY ${${PROJECT_NAME}_LOCAL_ACTION_DIR})
set(${PROJECT_NAME}_LOCAL_ACTION_DIR)
endif()
if(${PROJECT_NAME}_LOCAL_ACTION_DIR)
add_action_files(DIRECTORY action)
set(${PROJECT_NAME}_DO_MESSAGE_GENERATION TRUE)
endif()
# add message files if available
set(${PROJECT_NAME}_LOCAL_MSG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/msg)
if(NOT IS_DIRECTORY ${${PROJECT_NAME}_LOCAL_MSG_DIR})
set(${PROJECT_NAME}_LOCAL_MSG_DIR)
endif()
if(${PROJECT_NAME}_LOCAL_MSG_DIR)
add_message_files(DIRECTORY msg)
set(${PROJECT_NAME}_DO_MESSAGE_GENERATION TRUE)
endif()
# add service files if available
set(${PROJECT_NAME}_LOCAL_SRV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/srv)
if(NOT IS_DIRECTORY ${${PROJECT_NAME}_LOCAL_SRV_DIR})
set(${PROJECT_NAME}_LOCAL_SRV_DIR)
endif()
if(${PROJECT_NAME}_LOCAL_SRV_DIR)
add_service_files(DIRECTORY srv)
set(${PROJECT_NAME}_DO_MESSAGE_GENERATION TRUE)
endif()
# generate messages if necessary
if(${PROJECT_NAME}_DO_MESSAGE_GENERATION)
# identify all build dependencies which contain messages
set(${PROJECT_NAME}_MSG_PACKAGES)
foreach(dep ${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS})
set(${PROJECT_NAME}_MSG_PACKAGE_FILE ${${dep}_DIR}/${dep}-msg-paths.cmake)
if(EXISTS ${${PROJECT_NAME}_MSG_PACKAGE_FILE})
list(APPEND ${PROJECT_NAME}_MSG_PACKAGES ${dep})
endif()
endforeach()
generate_messages(DEPENDENCIES ${${PROJECT_NAME}_MSG_PACKAGES})
# add additional exported targets coming from generate_messages()
list(INSERT ${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS 0 ${${PROJECT_NAME}_EXPORTED_TARGETS})
endif()
endif()
# generate dynamic reconfigure files
if(dynamic_reconfigure_FOUND_CATKIN_PROJECT)
set(${PROJECT_NAME}_LOCAL_CFG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cfg)
if(IS_DIRECTORY ${${PROJECT_NAME}_LOCAL_CFG_DIR})
# create a list containing all the cfg files
file(GLOB ${PROJECT_NAME}_LOCAL_CFG_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${${PROJECT_NAME}_LOCAL_CFG_DIR}/*.cfg")
if(${PROJECT_NAME}_LOCAL_CFG_FILES)
generate_dynamic_reconfigure_options(${${PROJECT_NAME}_LOCAL_CFG_FILES})
# add build dep on gencfg
list(APPEND ${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS ${PROJECT_NAME}_gencfg)
endif()
endif()
endif()
endmacro()
macro(cs_add_targets_to_package)
add_dependencies(${PROJECT_NAME}_package ${ARGN})
list(APPEND ${PROJECT_NAME}_TARGETS ${ARGN})
endmacro()
macro(cs_add_executable _target)
if(${_target} STREQUAL ${PROJECT_NAME}_package)
message(WARNING "Could not create executable with name '${_target}' as '${PROJECT_NAME}_package' is reserved for the top level target name for this project.")
endif()
cmake_parse_arguments(cs_add_executable_args "NO_AUTO_LINK;NO_AUTO_DEP" "" "" ${ARGN})
add_executable(${_target} ${cs_add_executable_args_UNPARSED_ARGUMENTS})
if(NOT cs_add_executable_args_NO_AUTO_LINK)
target_link_libraries(${_target} ${catkin_LIBRARIES})
endif()
if(NOT cs_add_executable_args_NO_AUTO_DEP)
if(NOT "${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS}" STREQUAL "")
add_dependencies(${_target} ${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS})
endif()
endif()
cs_add_targets_to_package(${_target})
endmacro()
macro(cs_add_library _target)
if(${_target} STREQUAL ${PROJECT_NAME}_package)
message(WARNING "Could not create library with name '${_target}' as '${PROJECT_NAME}_package' is reserved for the top level target name for this project.")
endif()
cmake_parse_arguments(cs_add_library "NO_AUTO_LINK;NO_AUTO_DEP;NO_AUTO_EXPORT" "" "" ${ARGN})
add_library(${_target} ${cs_add_library_UNPARSED_ARGUMENTS})
if(NOT cs_add_library_NO_AUTO_LINK)
target_link_libraries(${_target} ${catkin_LIBRARIES})
endif()
if(NOT cs_add_library_NO_AUTO_DEP)
if(NOT "${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS}" STREQUAL "")
add_dependencies(${_target} ${${PROJECT_NAME}_CATKIN_BUILD_DEPENDS_EXPORTED_TARGETS})
endif()
endif()
if(NOT cs_add_library_NO_AUTO_EXPORT)
list(APPEND ${PROJECT_NAME}_LIBRARIES ${_target})
endif()
cs_add_targets_to_package(${_target})
endmacro()
macro(cs_install)
# Install targets (exec's and lib's)
foreach(_target ${${PROJECT_NAME}_TARGETS})
get_target_property(${_target}_type ${_target} TYPE)
message(STATUS "Marking ${${_target}_type} \"${_target}\" of package \"${PROJECT_NAME}\" for installation")
endforeach()
install(TARGETS ${${PROJECT_NAME}_TARGETS} ${ARGN}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
if(EXISTS ${${PROJECT_NAME}_LOCAL_INCLUDE_DIR})
# Install include directory
message(STATUS "Marking HEADER FILES in \"include\" folder of package \"${PROJECT_NAME}\" for installation")
install(DIRECTORY ${${PROJECT_NAME}_LOCAL_INCLUDE_DIR}/
DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
PATTERN ".svn" EXCLUDE
)
endif()
# Install shared content located in commonly used folders
set(_shared_content_folders launch rviz urdf meshes maps worlds Media param)
foreach(_folder ${_shared_content_folders})
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_folder})
message(STATUS "Marking SHARED CONTENT FOLDER \"${_folder}\" of package \"${PROJECT_NAME}\" for installation")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_folder}/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${_folder}
)
endif()
endforeach()
endmacro()
macro(cs_install_scripts)
install(PROGRAMS ${ARGN} DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
endmacro()
macro(cs_export)
cmake_parse_arguments(CS_PROJECT
"" "" "INCLUDE_DIRS;LIBRARIES;CATKIN_DEPENDS;DEPENDS;CFG_EXTRAS"
${ARGN})
set(${PROJECT_NAME}_CATKIN_RUN_DEPENDS)
foreach(dep ${${PROJECT_NAME}_RUN_DEPENDS})
find_package(${dep} QUIET)
if(${dep}_FOUND_CATKIN_PROJECT)
list(APPEND ${PROJECT_NAME}_CATKIN_RUN_DEPENDS ${dep})
endif()
endforeach()
catkin_package(
INCLUDE_DIRS ${${PROJECT_NAME}_LOCAL_INCLUDE_DIR} ${CS_PROJECT_INCLUDE_DIRS}
LIBRARIES ${${PROJECT_NAME}_LIBRARIES} ${CS_PROJECT_LIBRARIES}
CATKIN_DEPENDS ${${PROJECT_NAME}_CATKIN_RUN_DEPENDS} ${CS_PROJECT_CATKIN_DEPENDS}
DEPENDS ${CS_PROJECT_DEPENDS}
CFG_EXTRAS ${CS_PROJECT_CFG_EXTRAS}
)
endmacro()

View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<package>
<name>catkin_simple</name>
<version>0.1.1</version>
<description>catkin, simpler</description>
<maintainer email="william@osrfoundation.org">William Woodall</maintainer>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>BSD</license>
<author email="william@osrfoundation.org">William Woodall</author>
<author email="dthomas@osrfoundation.org">Dirk Thomas</author>
<buildtool_depend>catkin</buildtool_depend>
<run_depend>catkin</run_depend>
</package>

View File

@@ -0,0 +1,2 @@
Header header
string data

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<package>
<name>bar</name>
<version>0.1.0</version>
<description>The bar package</description>
<maintainer email="william@osrfoundation.org">William Woodall</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
<buildtool_depend>catkin_simple</buildtool_depend>
<run_depend>boost</run_depend>
<run_depend>message_runtime</run_depend>
<run_depend>std_msgs</run_depend>
<build_depend>boost-dev</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>std_msgs</build_depend>
</package>

View File

@@ -0,0 +1,16 @@
#include <bar/hello.h>
#include <bar/HeaderString.h>
#include <iostream>
#include <boost/thread.hpp>
inline void print_hello() {
std::cout << "Hello ";
}
void hello() {
boost::thread t(print_hello);
t.join();
}

View File

@@ -0,0 +1,12 @@
#include <iostream>
#include <boost/thread.hpp>
void print_world() {
std::cout << "world!" << std::endl;
}
void world() {
boost::thread t(print_world);
t.join();
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<package>
<name>baz</name>
<version>0.1.0</version>
<description>The baz package</description>
<maintainer email="william@osrfoundation.org">William Woodall</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
<run_depend>boost</run_depend>
<build_depend>boost-dev</build_depend>
</package>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<package>
<name>foo</name>
<version>0.1.0</version>
<description>The foo package</description>
<maintainer email="william@osrfoundation.org">William Woodall</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
<buildtool_depend>catkin_simple</buildtool_depend>
<run_depend>bar</run_depend>
<build_depend>bar</build_depend>
<run_depend>baz</run_depend>
<build_depend>baz</build_depend>
<run_depend>boost</run_depend>
<build_depend>boost-dev</build_depend>
</package>

View File

@@ -0,0 +1,9 @@
#include <bar/hello.h>
#include <baz/world.h>
int main(void) {
hello();
world();
return 0;
}

View File

@@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 2.8.3)
project(tools)
set(CMAKE_VERBOSE_MAKEFILE "true")
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "-std=c++14 -g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
find_package(Eigen3 REQUIRED)
find_package(PCL REQUIRED)
find_package(catkin REQUIRED COMPONENTS
roscpp
visualization_msgs
std_msgs
sensor_msgs
geometry_msgs
cv_bridge
decomp_ros_utils
)
include_directories(
include
${catkin_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
${DECOMP_UTIL_INCLUDE_DIRS}
)
#if this catkin packge's header is used by other packages, use catkin_package to
#declare the include directories of this package.
catkin_package(
INCLUDE_DIRS include
CATKIN_DEPENDS decomp_ros_utils
)

View File

@@ -0,0 +1,330 @@
#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <random>
#include <decomp_basis/data_type.h>
#include <Eigen/Eigen>
#include "gridmap.hpp"
namespace plan_utils
{
void corridorBuilder2d(Eigen::Vector2d origin, float radius, float max_x, float max_y,
vec_Vec2f &data, std::vector<Eigen::Vector2d> &add_data,
Eigen::MatrixXd &hPoly) {
//max_x max_y may be the local map?
//why add_data?
//radius = inf?
//origin is the root point of the poly
float interior_x = 0.0;
float interior_y = 0.0;
float safe_radius = radius;
std::vector<cv::Point2f> flipData;
cv::Point2f point;
vec_Vec2f new_data;
for (size_t i=0; i<data.size(); i++) {
float dx = data[i](0) - origin(0);
float dy = data[i](1) - origin(1);
float norm2 = std::sqrt(dx*dx + dy*dy);
if ( abs(dx) > max_x || abs(dy) > max_y) {
continue;
}
if (norm2 < safe_radius) safe_radius = norm2; //safe radius is the nearest distance between the root and obs
if (norm2 == 0) continue;
point.x = dx + 2*(radius-norm2)*dx/norm2;
point.y = dy + 2*(radius-norm2)*dy/norm2; //radius is an enough large value
new_data.push_back(data[i]);
flipData.push_back(point);
}
for (size_t i=0; i<add_data.size(); i++) {
float dx = add_data[i](0) - origin(0);
float dy = add_data[i](1) - origin(1);
float norm2 = std::sqrt(dx*dx + dy*dy);
if (norm2 < safe_radius) safe_radius = norm2;
if (norm2 == 0) continue;
point.x = dx + 2*(radius-norm2)*dx/norm2;
point.y = dy + 2*(radius-norm2)*dy/norm2;
new_data.push_back(add_data[i]);
flipData.push_back(point);
}
std::vector<int> vertexIndice;
cv::convexHull(flipData,vertexIndice,false,false);
//obtain the poly containing flipData
bool isOriginAVertex = false;
int OriginIndex = -1;
std::vector<cv::Point2f> vertexData;
for (size_t i=0; i<vertexIndice.size(); i++) {
unsigned int v = vertexIndice[i];
if (v == new_data.size()) {
isOriginAVertex = true;
OriginIndex = i;
vertexData.push_back(cv::Point2f(origin(0), origin(1)));
}else {
vertexData.push_back(cv::Point2f(new_data[v](0), new_data[v](1)));
}
}
if (isOriginAVertex) {
int last_index = (OriginIndex - 1)%vertexIndice.size();
int next_index = (OriginIndex + 1)%vertexIndice.size();
float dx = (new_data[vertexIndice[last_index]](0) + origin(0) + new_data[vertexIndice[next_index]](0))/3 - origin(0);
float dy = (new_data[vertexIndice[last_index]](1) + origin(1) + new_data[vertexIndice[next_index]](1))/3 - origin(1);
float d = std::sqrt(dx*dx + dy*dy);
interior_x = 0.99*safe_radius*dx/d + origin(0);
interior_y = 0.99*safe_radius*dy/d + origin(1);
}else {
interior_x = origin(0);
interior_y = origin(1);
}
std::vector<int> vIndex2;
cv::convexHull(vertexData,vIndex2,false,false); // counterclockwise right-hand
std::vector<Eigen::Vector3f> constraints; // (a,b,c) a x + b y <= c
for (size_t j=0; j<vIndex2.size(); j++) {
int jplus1 = (j+1)%vIndex2.size();
cv::Point2f rayV = vertexData[vIndex2[jplus1]] - vertexData[vIndex2[j]];
Eigen::Vector2f normalJ(rayV.y, -rayV.x); // point to outside
normalJ.normalize();
int indexJ = vIndex2[j];
while (indexJ != vIndex2[jplus1]) {
float c = (vertexData[indexJ].x-interior_x) * normalJ(0) + (vertexData[indexJ].y-interior_y) * normalJ(1);
constraints.push_back(Eigen::Vector3f(normalJ(0), normalJ(1), c));
indexJ = (indexJ+1)%vertexData.size();
}
}
std::vector<cv::Point2f> dualPoints(constraints.size(), cv::Point2f(0,0));
for (size_t i=0; i<constraints.size(); i++) {
dualPoints[i].x = constraints[i](0)/constraints[i](2);
dualPoints[i].y = constraints[i](1)/constraints[i](2);
}
std::vector<cv::Point2f> dualVertex, finalVertex;
cv::convexHull(dualPoints,dualVertex,true,false);
for (size_t i=0; i<dualVertex.size(); i++) {
int iplus1 = (i+1)%dualVertex.size();
cv::Point2f rayi = dualVertex[iplus1] - dualVertex[i];
float c = rayi.y*dualVertex[i].x - rayi.x*dualVertex[i].y;
finalVertex.push_back(cv::Point2f(interior_x+rayi.y/c, interior_y-rayi.x/c));
}
unsigned int size = finalVertex.size();
hPoly.resize(4, size);
for (unsigned int i = 0; i < size; i++){
int iplus1 = (i+1)%size;
cv::Point2f rayi = finalVertex[iplus1] - finalVertex[i];
hPoly.col(i).tail<2>() = Eigen::Vector2d(finalVertex[i].x, finalVertex[i].y); // the points on the plane
hPoly.col(i).head<2>() = Eigen::Vector2d(-rayi.y, rayi.x); // outside
}
}
Eigen::MatrixXd getDilateRec(Eigen::Vector3d state, map_util::OccMapUtil gridmap, int maxIndexL = 5, int maxIndexW = 8){
double resolution = gridmap.getRes();
double step = resolution * 1.0;
double limitBoundHalfL = maxIndexL * resolution;
double limitBoundHalfW = maxIndexW * resolution;
//generate a rectangle for this state px py yaw
//generate a hPoly
Eigen::Matrix<int,4,1> NotFinishTable = Eigen::Matrix<int,4,1>(1,1,1,1);
Eigen::Vector2d sourcePt = state.head(2);
double yaw = state[2];
Eigen::Vector4d expandLength;
expandLength << 0.0, 0.0, 0.0, 0.0;
Eigen::Matrix2d egoR;
egoR << cos(yaw), -sin(yaw),
sin(yaw), cos(yaw);
//dcr width length
while(NotFinishTable.norm()>0){
//+dx -dy -dx +dy
for(int i = 0; i<4; i++){
if(!NotFinishTable[i]) continue;
//get the new source and vp
Eigen::Vector4d tmp_expandLength = expandLength;
Eigen::Vector2d cor1, cor2, cor3, cor4, cor5;
bool isocc = false;
switch (i)
{
//+dx
case 0:
tmp_expandLength[0] += step;
cor1 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],tmp_expandLength[3]);
cor2 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],-tmp_expandLength[1]);
cor3 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],-tmp_expandLength[1]);
cor4 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],tmp_expandLength[3]);
cor5 = cor1;
//1 new1 new1 new2 new2 2
isocc = gridmap.isBlocked(cor1, cor2);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor2, cor3);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor3, cor4);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor4, cor5);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
if(tmp_expandLength[0] > limitBoundHalfL){
NotFinishTable[i] = 0.0;
break;
}
expandLength = tmp_expandLength;
break;
//-dy
case 1:
tmp_expandLength[1] += step;
cor1 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],tmp_expandLength[3]);
cor2 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],-tmp_expandLength[1]);
cor3 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],-tmp_expandLength[1]);
cor4 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],tmp_expandLength[3]);
cor5 = cor1;
//1 new1 new1 new2 new2 2
isocc = gridmap.isBlocked(cor1, cor2);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor2, cor3);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor3, cor4);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor4, cor5);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
if(tmp_expandLength[1] > limitBoundHalfW){
NotFinishTable[i] = 0.0;
break;
}
expandLength = tmp_expandLength;
break;
//-dx
case 2:
tmp_expandLength[2] += step;
cor1 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],tmp_expandLength[3]);
cor2 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],-tmp_expandLength[1]);
cor3 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],-tmp_expandLength[1]);
cor4 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],tmp_expandLength[3]);
cor5 = cor1;
//1 new1 new1 new2 new2 2
isocc = gridmap.isBlocked(cor1, cor2);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor2, cor3);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor3, cor4);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor4, cor5);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
if(tmp_expandLength[2] > limitBoundHalfL){
NotFinishTable[i] = 0.0;
break;
}
expandLength = tmp_expandLength;
break;
//dy
case 3:
tmp_expandLength[3] += step;
cor1 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],tmp_expandLength[3]);
cor2 = sourcePt + egoR * Eigen::Vector2d(tmp_expandLength[0],-tmp_expandLength[1]);
cor3 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],-tmp_expandLength[1]);
cor4 = sourcePt + egoR * Eigen::Vector2d(-tmp_expandLength[2],tmp_expandLength[3]);
cor5 = cor1;
//1 new1 new1 new2 new2 2
isocc = gridmap.isBlocked(cor1, cor2);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor2, cor3);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor3, cor4);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
isocc = gridmap.isBlocked(cor4, cor5);
if(isocc){
NotFinishTable[i] = 0.0;
break;
}
if(tmp_expandLength[3] > limitBoundHalfW){
NotFinishTable[i] = 0.0;
break;
}
expandLength = tmp_expandLength;
break;
}
}
}
Eigen::MatrixXd poly;
poly.resize(4,4);
std::vector<Eigen::Vector2d> cors;
cors.resize(4);
cors[0] = sourcePt + egoR * Eigen::Vector2d(expandLength[0],expandLength[3]);
cors[1] = sourcePt + egoR * Eigen::Vector2d(expandLength[0],-expandLength[1]);
cors[2] = sourcePt + egoR * Eigen::Vector2d(-expandLength[2],-expandLength[1]);
cors[3] = sourcePt + egoR * Eigen::Vector2d(-expandLength[2],expandLength[3]);
poly.col(0) << cors[0], cos(yaw), sin(yaw);
poly.col(1) << cors[1], sin(yaw), -cos(yaw);
poly.col(2) << cors[2], -cos(yaw), -sin(yaw);
poly.col(3) << cors[3],-sin(yaw), cos(yaw);
return poly;
}
bool ifInside(Eigen::Vector2d pt, Eigen::MatrixXd poly){
for(int i = 0; i < poly.cols(); i++){
Eigen::Vector2d p = poly.col(i).head(2);
Eigen::Vector2d n = poly.col(i).tail(2);
if((pt-p).dot(n)>0){
return false;
}
}
return true;
}
} // namespace plan_utils

View File

@@ -0,0 +1,144 @@
#ifndef CONFIG.HPP
#define CONFIG.HPP
#include <ros/ros.h>
#include <iostream>
#include <cmath>
#include <cfloat>
#include <vector>
#include <Eigen/Eigen>
#include <XmlRpcValue.h>
struct Config
{
double mini_T = 0.0;
double wei_time_ = 500.0;
double kmax = 0.45;
double vmax = 3.0;
double latAccmax = 3.0;
double lonAccmax = 3.0;
double accRatemax = 8.0;
double kdotmax = 5.0;
double yawdotmax = 3.14;
int traj_res = 16;
double scaling_wf_min_ = 0.01, scaling_wc_min_ = 0.01;
double rho = 1.0, rho_max =1000.0;
double gamma = 1;
double cons_eps_ = 0.20;
int mem_size = 256;
int past = 3; //3
double g_epsilon = 1.0e-3;
double min_step = 1.0e-32;
double delta = 1.0e-4;
int max_iterations = 12000;
int amlMaxIter = 15;
double pieceTime = 0.7;
XmlRpc::XmlRpcValue xmlconpts;
std::vector<Eigen::Vector2d> conpts;
/*map parameters*/
double mapRes = 0.1;
double mapX = 50.0, mapY = 50.0, mapZ = 10.0;
int expandSize = 1;
/*front end*/
double wheel_base = 0.6;
double horizon_ = 50.0;
double yaw_resolution_ = 0.3;
double lambda_heu_ = 5.0;
int allocate_num_ = 100000;
int check_num_ = 5;
double max_seach_time = 1.0;
double step_arc = 0.9;
double checkl = 0.2;
double non_siguav = 0.0;
double backW = 2.0;
double penaWei = 500.0;
double esdfWei = 1000.0;
double miniS =0.9;
bool isdebug = true;
bool isfixGear = false;
bool isVis = false;
bool enable_shot = false;
double safeMargin = 0.1;
bool useDP = true;
double phimax = 0.785;
double omegamax = 0.3;
double steer_res = 0.5;
std::string model_path = "/home/han/2023codes/NeuralTraj/model/big_cock.pt";
Config(const ros::NodeHandle &nh_priv)
{
nh_priv.param("mini_T", mini_T, 0.0);
nh_priv.param("wei_time_", wei_time_, 500.0);
nh_priv.param("kmax", kmax, 0.45);
nh_priv.param("vmax", vmax, 3.0);
nh_priv.param("latAccmax", latAccmax, 3.0);
nh_priv.param("lonAccmax", lonAccmax, 3.0);
nh_priv.param("accRatemax", accRatemax, 8.0);
nh_priv.param("kdotmax", kdotmax, 1.0);
nh_priv.param("yawdotmax", yawdotmax, 3.14);
nh_priv.param("traj_res", traj_res, 16);
nh_priv.param("rho", rho, 1.0);
nh_priv.param("rho_max", rho_max, 1000.0);
nh_priv.param("gamma", gamma, 1.0);
nh_priv.param("cons_eps_", cons_eps_, 0.2);
nh_priv.param("mem_size", mem_size, 256);
nh_priv.param("past", past, 3);
nh_priv.param("g_epsilon", g_epsilon, 1.0e-3);
nh_priv.param("min_step", min_step, 1.0e-32);
nh_priv.param("delta", delta, 1.0e-4);
nh_priv.param("max_iterations", max_iterations, 10000);
nh_priv.param("amlMaxIter", amlMaxIter, 15);
nh_priv.param("pieceTime", pieceTime, 0.7);
nh_priv.getParam("conpts", xmlconpts);
nh_priv.getParam("penaWei", penaWei);
nh_priv.getParam("esdfWei", esdfWei);
nh_priv.getParam("miniS", miniS);
nh_priv.getParam("safeMargin", safeMargin);
nh_priv.getParam("phimax", phimax);
nh_priv.getParam("omegamax", omegamax);
nh_priv.getParam("useDP", useDP);
nh_priv.getParam("steer_res", steer_res);
for(int i = 0; i < xmlconpts.size(); ++i)
{
Eigen::Vector2d pt;
for(int j = 0; j < 2; ++j)
{
pt[j] = xmlconpts[i][j];
}
conpts.push_back(pt);
}
nh_priv.param("mapRes", mapRes, 0.1);
nh_priv.param("mapX", mapX, 50.0);
nh_priv.param("mapY", mapY, 50.0);
nh_priv.param("expandSize", expandSize, 2);
nh_priv.param("wheel_base", wheel_base, 0.6);
nh_priv.param("horizon_", horizon_, 50.0);
nh_priv.param("yaw_resolution_", yaw_resolution_, 0.3);
nh_priv.param("lambda_heu_", lambda_heu_, 5.0);
nh_priv.param("allocate_num_", allocate_num_, 100000);
nh_priv.param("check_num_", check_num_, 5);
nh_priv.param("max_seach_time", max_seach_time, 1.0);
nh_priv.param("step_arc", step_arc, 0.9);
nh_priv.param("checkl", checkl, 0.2);
nh_priv.param("non_siguav", non_siguav, 0.0);
nh_priv.param("isdebug", isdebug, false);
nh_priv.param("isfixGear", isfixGear, false);
nh_priv.param("isVis", isVis, false);
nh_priv.param("enable_shot", enable_shot, false);
nh_priv.param("backW", backW, 2.0);
}
};
double normalize_angle(const double& theta) {
double theta_tmp = theta;
while(theta_tmp >= acos(-1.0)){
theta_tmp -= 2 * acos(-1.0);
}
while(theta_tmp < -acos(-1.0)){
theta_tmp += 2 * acos(-1.0);
}
return theta_tmp;
}
typedef std::shared_ptr<Config> ConfigPtr;
#endif

View File

@@ -0,0 +1,792 @@
#ifndef GRIDMAP_H
#define GRIDMAP_H
#include <iostream>
#include <ros/ros.h>
#include <ros/console.h>
#include <map>
#include <tools/config.hpp>
#include <decomp_basis/data_type.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
namespace map_util{
using Tmap = std::vector<signed char>;
template <int Dim> class MapUtil {
public:
///Simple constructor
MapUtil() {}
///Get map data
Tmap getMap() { return map_; }
//
bool has_map_(){return has_map;}
///Get resolution
double getRes() { return res_; }
///Get dimensions
Veci<Dim> getDim() { return dim_; }
///Get origin
Vecf<Dim> getOrigin() { return origin_d_; }
Vecf<Dim> getMapSize() { return map_size; }
void setParam(ConfigPtr config_, ros::NodeHandle& nh){
res_ = config_->mapRes;
int buffer_size;
expand_size = config_->expandSize;
priv_config_ = config_;
if(Dim == 3){
map_size(0) = config_->mapX;
map_size(1) = config_->mapY;
map_size(2) = config_->mapZ;
origin_d_[0] = -map_size(0)/2;
origin_d_[1] = -map_size(1)/2;
origin_d_[2] = 0;
dim_(0) = map_size(0)/res_;
dim_(1) = map_size(1)/res_;
dim_(2) = map_size(2)/res_;
buffer_size = dim_(0)*dim_(1)*dim_(2);
}
else if(Dim==2){
map_size(0) = config_->mapX + 1.0e-4;
map_size(1) = config_->mapY + 1.0e-4;
origin_d_[0] = -map_size(0)/2;
origin_d_[1] = -map_size(1)/2;
dim_(0) = map_size(0)/res_;
dim_(1) = map_size(1)/res_;
buffer_size = dim_(0)*dim_(1);
/*ESDF*/
distance_buffer_ = std::vector<double>(buffer_size, 10000);
distance_buffer_neg_ = std::vector<double>(buffer_size, 10000);
distance_buffer_all_ = std::vector<double>(buffer_size, 10000);
tmp_buffer1_ = std::vector<double>(buffer_size, 0);
occupancy_buffer_neg = std::vector<char>(buffer_size, 0);
esdf_pub_ = nh.advertise<sensor_msgs::PointCloud2>("/global_esdf", 10);
pcl_pub_ = nh.advertise<sensor_msgs::PointCloud2>("/global_pcl", 10);
}
else{
ROS_ERROR("grid map dimensions must be 2 or 3!");
}
map_.resize(buffer_size,val_free);
point_cloud_sub_ = nh.subscribe("/global_map", 10, &MapUtil::MapBuild, this);
}
void setEnv(const sensor_msgs::PointCloud2 & pointcloud_map){
//only used in 2D environment
int buffer_size;
buffer_size = dim_(0)*dim_(1);
distance_buffer_ = std::vector<double>(buffer_size, 10000);
distance_buffer_neg_ = std::vector<double>(buffer_size, 10000);
distance_buffer_all_ = std::vector<double>(buffer_size, 10000);
tmp_buffer1_ = std::vector<double>(buffer_size, 0);
occupancy_buffer_neg = std::vector<char>(buffer_size, 0);
std::fill(map_.begin(), map_.end(), val_free);
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::fromROSMsg(pointcloud_map, cloud);
if( (int)cloud.points.size() == 0 ) return;
pcl::PointXYZ pt;
for (int idx = 0; idx < (int)cloud.points.size(); idx++)
{
pt = cloud.points[idx];
setObs(pt);
}
has_map = true;
// std::cout << "!map build\n";
updateESDF2d();
publishESDF();
publishPCL();
}
void MapBuild(const sensor_msgs::PointCloud2 & pointcloud_map){
if(has_map) {
publishESDF();
return;}
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::fromROSMsg(pointcloud_map, cloud);
if( (int)cloud.points.size() == 0 ) return;
pcl::PointXYZ pt;
// cloud.points.clear();//data generaion
for (int idx = 0; idx < (int)cloud.points.size(); idx++)
{
pt = cloud.points[idx];
setObs(pt);
}
has_map = true;
updateESDF2d();
publishESDF();
}
void setObs(pcl::PointXYZ pt){
if(Dim==3){
double coord_x = pt.x;
double coord_y = pt.y;
double coord_z = pt.z;
Vec3f pt = Vec3f(coord_x,coord_y,coord_z);
Veci<Dim> index3i;
for(int i = 0; i < Dim; i++)
index3i(i) = std::round((pt(i) - origin_d_(i)) / res_ - 0.5);
if(isOutside(index3i))
return;
for (int i=-expand_size;i<=expand_size;i++)
for (int j=-expand_size;j<=expand_size;j++)
for (int k=-expand_size;k<=expand_size;k++)
{
Veci<Dim> temp_index;
temp_index(0) = index3i(0)+i;
temp_index(1) = index3i(1)+j;
temp_index(2) = index3i(2)+k;
if(isOutside(temp_index)) continue;
map_[getIndex(temp_index)] = val_occ;
}
}
else{
double coord_x = pt.x;
double coord_y = pt.y;
Vec2f pt = Vec2f(coord_x,coord_y);
Veci<Dim> index2i;
for(int i = 0; i < Dim; i++)
index2i(i) = std::round((pt(i) - origin_d_(i)) / res_ - 0.5);
if(isOutside(index2i))
return;
for (int i=-expand_size;i<=expand_size;i++)
for (int j=-expand_size;j<=expand_size;j++)
{
Veci<Dim> temp_index;
temp_index(0) = index2i(0)+i;
temp_index(1) = index2i(1)+j;
if(isOutside(temp_index)) continue;
map_[getIndex(temp_index)] = val_occ;
}
}
return;
}
///Get index of a cell
int getIndex(const Veci<Dim>& pn) {
return Dim == 2 ? pn(0) + dim_(0) * pn(1) :
pn(0) + dim_(0) * pn(1) + dim_(0) * dim_(1) * pn(2);
}
///Check if the given cell is outside of the map in i-the dimension
bool isOutsideXYZ(const Veci<Dim> &n, int i) { return n(i) < 0 || n(i) >= dim_(i); }
///Check if the cell is free by index
bool isFree(int idx) { return map_[idx] == val_free; }
///Check if the cell is unknown by index
bool isUnknown(int idx) { return map_[idx] == val_unknown; }
///Check if the cell is occupied by index
bool isOccupied(int idx) { return map_[idx] > val_free; }
//free 0 occ 100 unknow -1
///Check if the cell is outside by coordinate
bool isOutside(const Veci<Dim> &pn) {
for(int i = 0; i < Dim; i++)
if (pn(i) < 0 || pn(i) >= dim_(i))
return true;
return false;
}
///Check if the given cell is free by coordinate
bool isFree(const Veci<Dim> &pn) {
if (isOutside(pn))
return false;
else
return isFree(getIndex(pn));
}
///Check if the given cell is occupied by coordinate
bool isOccupied(const Veci<Dim> &pn) {
if (isOutside(pn))
return true;
else
return isOccupied(getIndex(pn));
}
bool isOccupied(const Vecf<Dim> &pt) {
Veci<Dim> pn = floatToInt(pt);
if (isOutside(pn))
return true;
else
return isOccupied(getIndex(pn));
}
///Check if the given cell is unknown by coordinate
bool isUnknown(const Veci<Dim> &pn) {
if (isOutside(pn))
return false;
return map_[getIndex(pn)] == val_unknown;
}
/**
* @brief Set map
*
* @param ori origin position
* @param dim number of cells in each dimension
* @param map array of cell values
* @param res map resolution
*/
void setMap(const Vecf<Dim>& ori, const Veci<Dim>& dim, const Tmap &map, double res) {
map_ = map;
dim_ = dim;
origin_d_ = ori;
res_ = res;
}
///Print basic information about the util
void info() {
Vecf<Dim> range = dim_.template cast<double>() * res_;
std::cout << "MapUtil Info ========================== " << std::endl;
std::cout << " res: [" << res_ << "]" << std::endl;
std::cout << " origin: [" << origin_d_.transpose() << "]" << std::endl;
std::cout << " range: [" << range.transpose() << "]" << std::endl;
std::cout << " dim: [" << dim_.transpose() << "]" << std::endl;
};
///Float position to discrete cell coordinate
Veci<Dim> floatToInt(const Vecf<Dim> &pt) {
Veci<Dim> pn;
for(int i = 0; i < Dim; i++)
pn(i) = floor((pt(i) - origin_d_(i)) / res_);
return pn;
}
///Discrete cell coordinate to float position
Vecf<Dim> intToFloat(const Veci<Dim> &pn) {
//return pn.template cast<double>() * res_ + origin_d_;
return (pn.template cast<double>() + Vecf<Dim>::Constant(0.5)) * res_ + origin_d_;
}
///Raytrace from float point pt1 to pt2
vec_Veci<Dim> rayTrace(const Vecf<Dim> &pt1, const Vecf<Dim> &pt2) {
Vecf<Dim> diff = pt2 - pt1;
double k = 0.8;
int max_diff = (diff / res_).template lpNorm<Eigen::Infinity>() / k;
double s = 1.0 / max_diff;
Vecf<Dim> step = diff * s;
vec_Veci<Dim> pns;
Veci<Dim> prev_pn = Veci<Dim>::Constant(-1);
for (int n = 1; n < max_diff; n++) {
Vecf<Dim> pt = pt1 + step * n;
Veci<Dim> new_pn = floatToInt(pt);
if (isOutside(new_pn))
break;
if (new_pn != prev_pn)
pns.push_back(new_pn);
prev_pn = new_pn;
}
return pns;
}
///Check if the ray from p1 to p2 is occluded
bool isBlocked(const Vecf<Dim>& p1, const Vecf<Dim>& p2, int8_t val = 100) {
vec_Veci<Dim> pns = rayTrace(p1, p2);
for (const auto &pn : pns) {
if (map_[getIndex(pn)] >= val)
return true;
}
return false;
}
///Get occupied voxels
vec_Vecf<Dim> getCloud() {
vec_Vecf<Dim> cloud;
Veci<Dim> n;
if(Dim == 3) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
for (n(2) = 0; n(2) < dim_(2); n(2)++) {
if (isOccupied(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
}
else if (Dim == 2) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
if (isOccupied(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
return cloud;
}
void updateESDF2d() {
if(Dim != 2){
ROS_ERROR("Dimension mismatch!");
}
Eigen::Vector2i min_esdf = Eigen::Vector2i(0,0);
Eigen::Vector2i max_esdf = Eigen::Vector2i(dim_(0) - 1, dim_(1) - 1);
/* ========== compute positive DT ========== */
for (int x = min_esdf[0]; x <= max_esdf[0]; x++) {
fillESDF(
[&](int y) {
return isOccupied(Vec2i(x, y))?
0 :
std::numeric_limits<double>::max();
},
[&](int y, double val) {tmp_buffer1_[getIndex(Vec2i(x, y))] = val; }, min_esdf[1],
max_esdf[1], 1);
}
for (int y = min_esdf[1]; y <= max_esdf[1]; y++) {
fillESDF([&](int x) { return tmp_buffer1_[getIndex(Vec2i(x, y))]; },
[&](int x, double val) {
distance_buffer_[getIndex(Vec2i(x, y))] = res_ * std::sqrt(val);
// min(mp_.resolution_ * std::sqrt(val),
// md_.distance_buffer_[toAddress(x, y, z)]);
},
min_esdf[0], max_esdf[0], 0);
}
/* ========== compute negative distance ========== */
for (int x = min_esdf(0); x <= max_esdf(0); ++x)
for (int y = min_esdf(1); y <= max_esdf(1); ++y)
{
int idx = getIndex(Vec2i(x, y));
if (isFree(idx)) {
occupancy_buffer_neg[idx] = 1;
} else if (isOccupied(idx)) {
occupancy_buffer_neg[idx] = 0;
} else {
ROS_ERROR("what?");
}
}
ros::Time t1, t2;
for (int x = min_esdf[0]; x <= max_esdf[0]; x++) {
fillESDF(
[&](int y) {
return occupancy_buffer_neg[getIndex(Vec2i(x, y))] == 1 ?
0 :
std::numeric_limits<double>::max();
},
[&](int y, double val) { tmp_buffer1_[getIndex(Vec2i(x, y))] = val; }, min_esdf[1],
max_esdf[1], 1);
}
for (int y = min_esdf[1]; y <= max_esdf[1]; y++) {
fillESDF([&](int x) { return tmp_buffer1_[getIndex(Vec2i(x, y))]; },
[&](int x, double val) {
distance_buffer_neg_[getIndex(Vec2i(x, y))] = res_ * std::sqrt(val);
},
min_esdf[0], max_esdf[0], 0);
}
/* ========== combine pos and neg DT ========== */
for (int x = min_esdf(0); x <= max_esdf(0); ++x)
for (int y = min_esdf(1); y <= max_esdf(1); ++y)
{
int idx = getIndex(Vec2i(x, y));
distance_buffer_all_[idx] = distance_buffer_[idx];
if (distance_buffer_neg_[idx] > 0.0){
distance_buffer_all_[idx] += (-distance_buffer_neg_[idx] + res_);
}
}
}
template <typename F_get_val, typename F_set_val>
void fillESDF(F_get_val f_get_val, F_set_val f_set_val, int start, int end, int d) {
int v[dim_(d)];
double z[dim_(d) + 1];
int k = start;
v[start] = start;
z[start] = -std::numeric_limits<double>::max();
z[start + 1] = std::numeric_limits<double>::max();
for (int q = start + 1; q <= end; q++) {
k++;
double s;
do {
k--;
s = ((f_get_val(q) + q * q) - (f_get_val(v[k]) + v[k] * v[k])) / (2 * q - 2 * v[k]);
} while (s <= z[k]);
k++;
v[k] = q;
z[k] = s;
z[k + 1] = std::numeric_limits<double>::max();
}
k = start;
for (int q = start; q <= end; q++) {
while (z[k + 1] < q) k++;
double val = (q - v[k]) * (q - v[k]) + f_get_val(v[k]);
f_set_val(q, val);
}
}
inline double getDistance(const Eigen::Vector2d& pos) {
Eigen::Vector2i id;
id = floatToInt(pos);
boundIndex(id);
return distance_buffer_all_[getIndex(id)];
}
inline double getDistance(const Eigen::Vector2i& id) {
Eigen::Vector2i id1 = id;
boundIndex(id1);
return distance_buffer_all_[getIndex(id1)];
}
inline void boundIndex(Eigen::Vector2i& id) {
Eigen::Vector2i id1;
id1(0) = std::max(std::min(id(0), dim_(0) - 1), 0);
id1(1) = std::max(std::min(id(1), dim_(1) - 1), 0);
id = id1;
}
void publishPCL(){
vec_Vecf<Dim> pcs = getCloud();
pcl::PointCloud<pcl::PointXYZI> cloud;
pcl::PointXYZI pt;
for(const auto& pc : pcs){
pt.x = pc[0];
pt.y = pc[1];
pt.z = 0.0;
cloud.push_back(pt);
}
cloud.width = cloud.points.size();
cloud.height = 1;
cloud.is_dense = true;
cloud.header.frame_id = "world";
sensor_msgs::PointCloud2 cloud_msg;
pcl::toROSMsg(cloud, cloud_msg);
pcl_pub_.publish(cloud_msg);
}
void publishESDF() {
double dist;
pcl::PointCloud<pcl::PointXYZI> cloud;
pcl::PointXYZI pt;
const double min_dist = -4.0;
const double max_dist = 4.0;
Eigen::Vector2i min_cut = Eigen::Vector2i(0,0);
Eigen::Vector2i max_cut = Eigen::Vector2i(dim_(0)-1,dim_(1)-1);
for (int x = min_cut(0); x <= max_cut(0); ++x)
for (int y = min_cut(1); y <= max_cut(1); ++y) {
Vec2f pos;
pos = intToFloat(Vec2i(x, y));
dist = getDistance(pos);
// if(dist<min_dist) dist = min_dist;
// if(dist>max_dist) dist = max_dist;
pt.x = pos(0);
pt.y = pos(1);
pt.z = dist;
pt.intensity = (dist - min_dist) / (max_dist - min_dist);
cloud.push_back(pt);
// }
}
cloud.width = cloud.points.size();
cloud.height = 1;
cloud.is_dense = true;
cloud.header.frame_id = "world";
sensor_msgs::PointCloud2 cloud_msg;
pcl::toROSMsg(cloud, cloud_msg);
esdf_pub_.publish(cloud_msg);
}
inline double getDistGrad(Eigen::Vector2d po, Eigen::Vector2d& grad) {
Eigen::Vector2d pos(po(0),po(1));
if (isOutside(floatToInt(pos))) {
grad.setZero();
return 0;
}
/* use bilinear interpolation */
Eigen::Vector2d pos_m = pos - 0.5 * res_ * Eigen::Vector2d::Ones();
Eigen::Vector2i idx;
idx = floatToInt(pos_m);
Eigen::Vector2d idx_pos, diff;
idx_pos = intToFloat(idx);
diff = (pos - idx_pos) / res_;
double values[2][2];
for (int x = 0; x < 2; x++) {
for (int y = 0; y < 2; y++) {
Eigen::Vector2i current_idx = idx + Eigen::Vector2i(x, y);
values[x][y] = getDistance(current_idx);
}
}
double v00 = (1-diff(0)) * values[0][0] + diff(0) * values[1][0];
double v10 = (1-diff(0)) * values[0][1] + diff(0) * values[1][1];
double v0 = (1-diff(1)) * v00 + diff(1) * v10;
// double dist = v0;
grad[1] = (v10 - v00) / res_;
grad[0] = ((1-diff(1)) * (values[1][0]-values[0][0]) + diff(1) * (values[1][1]-values[0][1])) / res_;
return v0;
}
///Get free voxels
vec_Vecf<Dim> getFreeCloud() {
vec_Vecf<Dim> cloud;
Veci<Dim> n;
if(Dim == 3) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
for (n(2) = 0; n(2) < dim_(2); n(2)++) {
if (isFree(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
}
else if (Dim == 2) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
if (isFree(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
return cloud;
}
///Get unknown voxels
vec_Vecf<Dim> getUnknownCloud() {
vec_Vecf<Dim> cloud;
Veci<Dim> n;
if(Dim == 3) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
for (n(2) = 0; n(2) < dim_(2); n(2)++) {
if (isUnknown(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
}
else if (Dim == 2) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
if (isUnknown(getIndex(n)))
cloud.push_back(intToFloat(n));
}
}
}
return cloud;
}
///Dilate occupied cells
void dilate(const vec_Veci<Dim>& dilate_neighbor) {
Tmap map = map_;
Veci<Dim> n = Veci<Dim>::Zero();
if(Dim == 3) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
for (n(2) = 0; n(2) < dim_(2); n(2)++) {
if (isOccupied(getIndex(n))) {
for (const auto &it : dilate_neighbor) {
if (!isOutside(n + it))
map[getIndex(n + it)] = val_occ;
}
}
}
}
}
}
else if(Dim == 2) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
if (isOccupied(getIndex(n))) {
for (const auto &it : dilate_neighbor) {
if (!isOutside(n + it))
map[getIndex(n + it)] = val_occ;
}
}
}
}
}
map_ = map;
}
///Free unknown voxels
void freeUnknown() {
Veci<Dim> n;
if(Dim == 3) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
for (n(2) = 0; n(2) < dim_(2); n(2)++) {
if (isUnknown(getIndex(n)))
map_[getIndex(n)] = val_free;
}
}
}
}
else if (Dim == 2) {
for (n(0) = 0; n(0) < dim_(0); n(0)++) {
for (n(1) = 0; n(1) < dim_(1); n(1)++) {
if (isUnknown(getIndex(n)))
map_[getIndex(n)] = val_free;
}
}
}
}
void CheckIfCollisionUsingPosAndYaw(const Eigen::Vector3d &state, bool *res, double flat = 0.0){
if(Dim==3){
ROS_ERROR("CheckIfCollisionUsingPosAndYaw Only works with Dimension = 2!");
return;
}
else{
Eigen::Matrix2d rotM;
double yaw = state[2];
rotM << cos(yaw), -sin(yaw),
sin(yaw), cos(yaw);
Eigen::Vector2d p = state.head(2);
for(int i = 0; i < priv_config_->conpts.size(); i++){
// Eigen::Vector2d rep1 = priv_config_->conpts[i];
// Eigen::Vector2d rep2 = priv_config_->conpts[(i+1)%priv_config_->conpts.size()];
// if(rep1[0] > 0){
// rep1[0] += res_;
// }
// else{
// rep1[0] -= res_;
// }
// if(rep1[1] > 0){
// rep1[1] += res_;
// }
// else{
// rep1[1] -= res_;
// }
// if(rep2[0] > 0){
// rep2[0] += res_;
// }
// else{
// rep2[0] -= res_;
// }
// if(rep2[1] > 0){
// rep2[1] += res_;
// }
// else{
// rep2[1] -= res_;
// }
// Eigen::Vector2d pt1 = p + rotM * rep1;
// Eigen::Vector2d pt2 = p + rotM * rep2;
// if(isBlocked(pt1, pt2)){
// *res = true;
// return;
// }
Eigen::Vector2d pt = p + rotM * priv_config_->conpts[i];
Eigen::Vector2d grad;
// if(flat > 0){
// std::cout << "dis: "<<getDistGrad(pt, grad)<<"\n";
// }
if(getDistGrad(pt, grad)<priv_config_->safeMargin + flat){
*res = true;
return;
}
}
}
*res = false;
return;
}
void CheckIfCollisionForBackEnd(const Eigen::Vector3d &state, bool *res){
if(Dim==3){
ROS_ERROR("CheckIfCollisionUsingPosAndYaw Only works with Dimension = 2!");
return;
}
else{
Eigen::Matrix2d rotM;
double yaw = state[2];
rotM << cos(yaw), -sin(yaw),
sin(yaw), cos(yaw);
Eigen::Vector2d p = state.head(2);
for(int i = 0; i < priv_config_->conpts.size(); i++){
// Eigen::Vector2d rep1 = priv_config_->conpts[i];
// Eigen::Vector2d rep2 = priv_config_->conpts[(i+1)%priv_config_->conpts.size()];
// if(rep1[0] > 0){
// rep1[0] += res_;
// }
// else{
// rep1[0] -= res_;
// }
// if(rep1[1] > 0){
// rep1[1] += res_;
// }
// else{
// rep1[1] -= res_;
// }
// if(rep2[0] > 0){
// rep2[0] += res_;
// }
// else{
// rep2[0] -= res_;
// }
// if(rep2[1] > 0){
// rep2[1] += res_;
// }
// else{
// rep2[1] -= res_;
// }
// Eigen::Vector2d pt1 = p + rotM * rep1;
// Eigen::Vector2d pt2 = p + rotM * rep2;
// if(isBlocked(pt1, pt2)){
// *res = true;
// return;
// }
Eigen::Vector2d pt = p + rotM * priv_config_->conpts[i];
Eigen::Vector2d grad;
if(getDistGrad(pt, grad)<priv_config_->safeMargin){
*res = true;
return;
}
}
}
*res = false;
return;
}
///Map entity
Tmap map_;
std::vector<double> distance_buffer_;
std::vector<double> distance_buffer_neg_;
std::vector<char> occupancy_buffer_neg;
std::vector<double> distance_buffer_all_;
std::vector<double> tmp_buffer1_;
std::string world_frame_id;
protected:
///Resolution
double res_;
///Origin, float type
Vecf<Dim> origin_d_;
///Dimension, int type
Veci<Dim> dim_;
Vecf<Dim> map_size;
///Assume occupied cell has value 100
int8_t val_occ = 100;
///Assume free cell has value 0
int8_t val_free = 0;
///Assume unknown cell has value -1
int8_t val_unknown = -1;
///inflate size
int expand_size = 1;
bool has_map = false;
ros::Subscriber point_cloud_sub_;
ConfigPtr priv_config_;
ros::Publisher esdf_pub_;
ros::Publisher pcl_pub_;
};
typedef MapUtil<2> OccMapUtil;
typedef MapUtil<3> VoxelMapUtil;
}
#endif

View File

@@ -0,0 +1,53 @@
/**
* @file tic_toc.h
* @author HKUST Aerial Robotics Group
* @brief
* @version 0.1
* @date 2019-03-17
*
* @copyright Copyright (c) 2019
*/
#ifndef _COMMON_INC_COMMON_BASICS_TIC_TOC_H_
#define _COMMON_INC_COMMON_BASICS_TIC_TOC_H_
#include <chrono>
#include <cstdlib>
#include <ctime>
class TicToc {
public:
TicToc() { tic(); }
/**
* @brief start timing
* @note the unit of time is in millisecond (ms)
*/
void tic() { start = std::chrono::system_clock::now(); }
/**
* @brief get time elapsed
* @note the unit of time is in millisecond (ms)
*/
double toc() {
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
return elapsed_seconds.count() * 1000;
}
/**
* @brief Convert chrono::system_clock::time_point to double
*
* @param t
* @return double
*/
static double TimePointToDouble(
const std::chrono::system_clock::time_point& t) {
auto tt = std::chrono::duration<double>(t.time_since_epoch());
return tt.count();
}
private:
std::chrono::time_point<std::chrono::system_clock> start, end;
};
#endif

View File

@@ -0,0 +1,619 @@
/*
MIT License
Copyright (c) 2020 Jialin Ji ()
2021 Hongkai Ye (kyle_yeh@163.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <nav_msgs/Path.h>
#include <pcl_conversions/pcl_conversions.h>
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <visualization_msgs/MarkerArray.h>
#include <decomp_util/ellipsoid_decomp.h>
#include <decomp_ros_utils/data_ros_utils.h>
#include <Eigen/Geometry>
#include <iostream>
#include <unordered_map>
namespace visualization {
struct BALL {
Eigen::Vector3d center;
double radius;
BALL(const Eigen::Vector3d& c, double r) : center(c), radius(r){};
BALL(){};
};
using PublisherMap = std::unordered_map<std::string, ros::Publisher>;
enum Color { white,
red,
green,
blue,
yellow,
chartreuse,
black,
gray,
orange,
purple,
pink,
steelblue };
class Visualization {
private:
ros::NodeHandle nh_;
PublisherMap publisher_map_;
void setMarkerColor(visualization_msgs::Marker& marker,
Color color = blue,
double a = 1) {
marker.color.a = a;
switch (color) {
case white:
marker.color.r = 1;
marker.color.g = 1;
marker.color.b = 1;
break;
case red:
marker.color.r = 1;
marker.color.g = 0;
marker.color.b = 0;
break;
case green:
marker.color.r = 0;
marker.color.g = 1;
marker.color.b = 0;
break;
case blue:
marker.color.r = 0;
marker.color.g = 0;
marker.color.b = 1;
break;
case yellow:
marker.color.r = 1;
marker.color.g = 1;
marker.color.b = 0;
break;
case chartreuse:
marker.color.r = 0.5;
marker.color.g = 1;
marker.color.b = 0;
break;
case black:
marker.color.r = 0;
marker.color.g = 0;
marker.color.b = 0;
break;
case gray:
marker.color.r = 0.5;
marker.color.g = 0.5;
marker.color.b = 0.5;
break;
case orange:
marker.color.r = 1;
marker.color.g = 0.5;
marker.color.b = 0;
break;
case purple:
marker.color.r = 0.5;
marker.color.g = 0;
marker.color.b = 1;
break;
case pink:
marker.color.r = 1;
marker.color.g = 0;
marker.color.b = 0.6;
break;
case steelblue:
marker.color.r = 0.4;
marker.color.g = 0.7;
marker.color.b = 1;
break;
}
}
void setMarkerColor(visualization_msgs::Marker& marker,
double a,
double r,
double g,
double b) {
marker.color.a = a;
marker.color.r = r;
marker.color.g = g;
marker.color.b = b;
}
void setMarkerScale(visualization_msgs::Marker& marker,
const double& x,
const double& y,
const double& z) {
marker.scale.x = x;
marker.scale.y = y;
marker.scale.z = z;
}
void setMarkerPose(visualization_msgs::Marker& marker,
const double& x,
const double& y,
const double& z) {
marker.pose.position.x = x;
marker.pose.position.y = y;
marker.pose.position.z = z;
marker.pose.orientation.w = 1;
marker.pose.orientation.x = 0;
marker.pose.orientation.y = 0;
marker.pose.orientation.z = 0;
}
template <class ROTATION>
void setMarkerPose(visualization_msgs::Marker& marker,
const double& x,
const double& y,
const double& z,
const ROTATION& R) {
marker.pose.position.x = x;
marker.pose.position.y = y;
marker.pose.position.z = z;
Eigen::Quaterniond r(R);
marker.pose.orientation.w = r.w();
marker.pose.orientation.x = r.x();
marker.pose.orientation.y = r.y();
marker.pose.orientation.z = r.z();
}
public:
Visualization(ros::NodeHandle& nh) : nh_(nh) {}
template <class CENTER, class TOPIC>
void visualize_a_ball(const CENTER& c,
const double& r,
const TOPIC& topic,
const Color color = blue,
const double a = 1) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<visualization_msgs::Marker>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker marker;
marker.header.frame_id = "world";
marker.type = visualization_msgs::Marker::SPHERE;
marker.action = visualization_msgs::Marker::ADD;
setMarkerColor(marker, color, a);
setMarkerScale(marker, 2 * r, 2 * r, 2 * r);
setMarkerPose(marker, c[0], c[1], c[2]);
marker.header.stamp = ros::Time::now();
publisher_map_[topic].publish(marker);
}
template <class PC, class TOPIC>
void visualize_pointcloud(const PC& pc, const TOPIC& topic) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<sensor_msgs::PointCloud2>(topic, 10);
publisher_map_[topic] = pub;
}
pcl::PointCloud<pcl::PointXYZ> point_cloud;
sensor_msgs::PointCloud2 point_cloud_msg;
point_cloud.reserve(pc.size());
for (const auto& pt : pc) {
if(pt.size()==3){
point_cloud.points.emplace_back(pt[0], pt[1], pt[2]);
}
else{
point_cloud.points.emplace_back(pt[0], pt[1], 0.0);
}
}
pcl::toROSMsg(point_cloud, point_cloud_msg);
point_cloud_msg.header.frame_id = "world";
point_cloud_msg.header.stamp = ros::Time::now();
publisher_map_[topic].publish(point_cloud_msg);
}
template <class PATH, class TOPIC>
void visualize_path(const PATH& path, const TOPIC& topic) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<nav_msgs::Path>(topic, 10);
publisher_map_[topic] = pub;
}
nav_msgs::Path path_msg;
geometry_msgs::PoseStamped tmpPose;
tmpPose.header.frame_id = "world";
for (const auto& pt : path) {
if(pt.size() == 3){
tmpPose.pose.position.x = pt[0];
tmpPose.pose.position.y = pt[1];
tmpPose.pose.position.z = pt[2];
}
else if(pt.size()==2){
tmpPose.pose.position.x = pt[0];
tmpPose.pose.position.y = pt[1];
tmpPose.pose.position.z = 0.0;
}
else{
ROS_ERROR("Dim must be 2 or 3 ");
}
path_msg.poses.push_back(tmpPose);
}
path_msg.header.frame_id = "world";
path_msg.header.stamp = ros::Time::now();
publisher_map_[topic].publish(path_msg);
}
template <class BALLS, class TOPIC>
void visualize_balls(const BALLS& balls,
const TOPIC& topic,
const Color color = blue,
const double a = 0.2) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<visualization_msgs::MarkerArray>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker marker;
marker.header.frame_id = "world";
marker.type = visualization_msgs::Marker::SPHERE;
marker.action = visualization_msgs::Marker::ADD;
marker.id = 0;
setMarkerColor(marker, color, a);
visualization_msgs::MarkerArray marker_array;
marker_array.markers.reserve(balls.size() + 1);
marker.action = visualization_msgs::Marker::DELETEALL;
marker_array.markers.push_back(marker);
marker.action = visualization_msgs::Marker::ADD;
for (const auto& ball : balls) {
setMarkerPose(marker, ball.center[0], ball.center[1], ball.center[2]);
auto d = 2 * ball.radius;
setMarkerScale(marker, d, d, d);
marker_array.markers.push_back(marker);
marker.id++;
}
publisher_map_[topic].publish(marker_array);
}
template <class ELLIPSOID, class TOPIC>
void visualize_ellipsoids(const ELLIPSOID& ellipsoids,
const TOPIC& topic,
const Color color = blue,
const double a = 0.2) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<visualization_msgs::MarkerArray>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker marker;
marker.header.frame_id = "world";
marker.type = visualization_msgs::Marker::SPHERE;
marker.action = visualization_msgs::Marker::ADD;
marker.id = 0;
setMarkerColor(marker, color, a);
visualization_msgs::MarkerArray marker_array;
marker_array.markers.reserve(ellipsoids.size() + 1);
marker.action = visualization_msgs::Marker::DELETEALL;
marker_array.markers.push_back(marker);
marker.action = visualization_msgs::Marker::ADD;
for (const auto& e : ellipsoids) {
setMarkerPose(marker, e.c[0], e.c[1], e.c[2], e.R);
setMarkerScale(marker, 2 * e.rx, 2 * e.ry, 2 * e.rz);
marker_array.markers.push_back(marker);
marker.id++;
}
publisher_map_[topic].publish(marker_array);
}
template <class PAIRLINE, class TOPIC>
// eg for PAIRLINE: std::vector<std::pair<Eigen::Vector3d, Eigen::Vector3d>>
void visualize_pairline(const PAIRLINE& pairline, const TOPIC& topic, const Color& color = green, double scale = 0.1) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<visualization_msgs::Marker>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker marker;
marker.header.frame_id = "world";
marker.type = visualization_msgs::Marker::LINE_LIST;
marker.action = visualization_msgs::Marker::ADD;
setMarkerPose(marker, 0, 0, 0);
setMarkerColor(marker, color, 1);
setMarkerScale(marker, scale, scale, scale);
marker.points.resize(2 * pairline.size());
for (size_t i = 0; i < pairline.size(); ++i) {
marker.points[2 * i + 0].x = pairline[i].first[0];
marker.points[2 * i + 0].y = pairline[i].first[1];
marker.points[2 * i + 0].z = pairline[i].first[2];
marker.points[2 * i + 1].x = pairline[i].second[0];
marker.points[2 * i + 1].y = pairline[i].second[1];
marker.points[2 * i + 1].z = pairline[i].second[2];
}
publisher_map_[topic].publish(marker);
}
template <class ARROWS, class TOPIC>
// ARROWS: pair<Vector3d, Vector3d>
void visualize_arrows(const ARROWS& arrows, const TOPIC& topic, const Color& color) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<visualization_msgs::MarkerArray>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker clear_previous_msg;
clear_previous_msg.action = visualization_msgs::Marker::DELETEALL;
visualization_msgs::Marker arrow_msg;
arrow_msg.type = visualization_msgs::Marker::ARROW;
arrow_msg.action = visualization_msgs::Marker::ADD;
arrow_msg.header.frame_id = "world";
arrow_msg.id = 0;
arrow_msg.points.resize(2);
setMarkerPose(arrow_msg, 0, 0, 0);
setMarkerScale(arrow_msg, 0.02, 0.12, 0);
setMarkerColor(arrow_msg, color, 0.7);
visualization_msgs::MarkerArray arrow_list_msg;
arrow_list_msg.markers.reserve(1 + arrows.size());
arrow_list_msg.markers.push_back(clear_previous_msg);
for (const auto& arrow : arrows) {
if(arrow.first.size()==3){
arrow_msg.points[0].x = arrow.first[0];
arrow_msg.points[0].y = arrow.first[1];
arrow_msg.points[0].z = arrow.first[2];
arrow_msg.points[1].x = arrow.second[0];
arrow_msg.points[1].y = arrow.second[1];
arrow_msg.points[1].z = arrow.second[2];
}
else{
arrow_msg.points[0].x = arrow.first[0];
arrow_msg.points[0].y = arrow.first[1];
arrow_msg.points[0].z = 4.0;
arrow_msg.points[1].x = arrow.second[0];
arrow_msg.points[1].y = arrow.second[1];
arrow_msg.points[1].z = 4.0;
}
arrow_list_msg.markers.push_back(arrow_msg);
arrow_msg.id += 1;
}
publisher_map_[topic].publish(arrow_list_msg);
}
template <class TRAJ, class TOPIC>
// TRAJ:
void visualize_traj(const TRAJ& traj, const TOPIC& topic) {
std::vector<Eigen::Vector3d> path;
auto duration = traj.getTotalDuration();
for (double t = 0; t < duration; t += 0.01) {
Eigen::VectorXd pos = traj.getPos(t);
if(pos.size()==3){
Eigen::Vector3d p3;
p3 << pos;
path.push_back(p3);
}
else if (pos.size()==2){
Eigen::Vector3d p3;
p3 << pos, 0.0;
path.push_back(p3);
}
else{
ROS_ERROR("Dim must be 3 or 2!");
}
}
visualize_path(path, topic);
// std::vector<Eigen::Vector3d> wayPts;
// for (const auto& piece : traj) {
// wayPts.push_back(piece.getPos(0));
// }
// visualize_pointcloud(wayPts, std::string(topic) + "_wayPts");
}
template <class TRAJ, class TOPIC>
// TRAJ:
void visualize_se2traj(const TRAJ& traj, const TOPIC& topic) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<visualization_msgs::Marker>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker carMarkers;
auto duration = traj.getTotalDuration();
for (double t = 0; t < duration; t += 0.3) {
Eigen::Vector2d pos = traj.getPos(t);
double yaw = traj.getYaw(t);
carMarkers.action = visualization_msgs::Marker::ADD;
carMarkers.id = 0;
carMarkers.type = visualization_msgs::Marker::LINE_LIST;
carMarkers.pose.orientation.w = 1.00;
carMarkers.ns = "se2traj";
carMarkers.color.r = 0.00;
carMarkers.color.g = 0.00;
carMarkers.color.b = 0.5;
carMarkers.color.a = 1.00;
carMarkers.scale.x = 0.05;
carMarkers.header.frame_id = "world";
geometry_msgs::Point point1;
geometry_msgs::Point point2;
geometry_msgs::Point point3;
geometry_msgs::Point point4;
Eigen::Matrix2d R;
R << cos(yaw),-sin(yaw),
sin(yaw),cos(yaw);
Eigen::Vector2d offset1, tmp1;
offset1 = R*Eigen::Vector2d(0.68,0.23);
tmp1 = pos+offset1;
point1.x = tmp1[0];
point1.y = tmp1[1];
point1.z = 0;
Eigen::Vector2d offset2, tmp2;
offset2 = R*Eigen::Vector2d(0.68, -0.23);
tmp2 = pos+offset2;
point2.x = tmp2[0];
point2.y = tmp2[1];
point2.z = 0;
Eigen::Vector2d offset3, tmp3;
offset3 = R*Eigen::Vector2d(-0.08, -0.23);
tmp3 = pos+offset3;
point3.x = tmp3[0];
point3.y = tmp3[1];
point3.z = 0;
Eigen::Vector2d offset4, tmp4;
offset4 = R*Eigen::Vector2d(-0.08, 0.23);
tmp4 = pos+offset4;
point4.x = tmp4[0];
point4.y = tmp4[1];
point4.z = 0;
carMarkers.points.push_back(point1);
carMarkers.points.push_back(point2);
carMarkers.points.push_back(point2);
carMarkers.points.push_back(point3);
carMarkers.points.push_back(point3);
carMarkers.points.push_back(point4);
carMarkers.points.push_back(point4);
carMarkers.points.push_back(point1);
}
carMarkers.header.stamp = ros::Time::now();
publisher_map_[topic].publish(carMarkers);
// std::vector<Eigen::Vector3d> wayPts;
// for (const auto& piece : traj) {
// wayPts.push_back(piece.getPos(0));
// }
// visualize_pointcloud(wayPts, std::string(topic) + "_wayPts");
}
template <class TRAJLIST, class TOPIC>
// TRAJLIST: std::vector<TRAJ>
void visualize_traj_list(const TRAJLIST& traj_list, const TOPIC& topic,
const Color color = blue, double scale = 0.1) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<visualization_msgs::MarkerArray>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker clear_previous_msg;
clear_previous_msg.action = visualization_msgs::Marker::DELETEALL;
visualization_msgs::Marker path_msg;
path_msg.type = visualization_msgs::Marker::LINE_STRIP;
path_msg.action = visualization_msgs::Marker::ADD;
path_msg.header.frame_id = "world";
path_msg.id = 0;
setMarkerPose(path_msg, 0, 0, 0);
setMarkerScale(path_msg, scale, scale, scale);
visualization_msgs::MarkerArray path_list_msg;
path_list_msg.markers.reserve(1 + traj_list.size());
path_list_msg.markers.push_back(clear_previous_msg);
// double a_step = 0.8 / traj_list.size();
double a = 1.0;
geometry_msgs::Point p_msg;
for (const auto& traj : traj_list) {
setMarkerColor(path_msg, color, a);
// a = a + a_step;
path_msg.points.clear();
for (double t = 0; t < traj.getDuration(); t += 0.01) {
auto p = traj.getSigma(t);
if(p.size()==3){
p_msg.x = p[0];
p_msg.y = p[1];
p_msg.z = p[2];
}
else{
p_msg.x = p[0];
p_msg.y = p[1];
p_msg.z = 0.0;
}
path_msg.points.push_back(p_msg);
}
path_list_msg.markers.push_back(path_msg);
path_msg.id += 1;
}
publisher_map_[topic].publish(path_list_msg);
}
template <class PATHLIST, class TOPIC>
// PATHLIST: std::vector<PATH>
void visualize_path_list(const PATHLIST& path_list, const TOPIC& topic,
const Color color = steelblue, double scale = 0.1) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<visualization_msgs::MarkerArray>(topic, 10);
publisher_map_[topic] = pub;
}
visualization_msgs::Marker clear_previous_msg;
clear_previous_msg.action = visualization_msgs::Marker::DELETEALL;
visualization_msgs::Marker path_msg;
path_msg.type = visualization_msgs::Marker::LINE_STRIP;
path_msg.action = visualization_msgs::Marker::ADD;
path_msg.header.frame_id = "world";
path_msg.id = 0;
setMarkerPose(path_msg, 0, 0, 0);
setMarkerScale(path_msg, scale, scale, scale);
visualization_msgs::MarkerArray path_list_msg;
path_list_msg.markers.reserve(1 + path_list.size());
path_list_msg.markers.push_back(clear_previous_msg);
setMarkerColor(path_msg, color);
for (const auto& path : path_list) {
path_msg.points.resize(path.size());
for (size_t i = 0; i < path.size(); ++i) {
path_msg.points[i].x = path[i].x();
path_msg.points[i].y = path[i].y();
path_msg.points[i].z = path[i].z();
}
path_list_msg.markers.push_back(path_msg);
path_msg.id += 1;
}
publisher_map_[topic].publish(path_list_msg);
}
template <class SFCS, class TOPIC>
// SFCS: std::vector<Eigen::MatrixXd>
void visualize_sfc(const SFCS& hPolys, const TOPIC& topic) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub =
nh_.advertise<decomp_ros_msgs::PolyhedronArray>(topic, 10);
publisher_map_[topic] = pub;
}
vec_E<Polyhedron2D> polyhedra;
polyhedra.reserve(hPolys.size());
for (const Eigen::MatrixXd &ele : hPolys){
Polyhedron2D hPoly;
for (int i = 0; i < ele.cols(); i++){
hPoly.add(Hyperplane2D(ele.col(i).tail<2>(), ele.col(i).head<2>()));
}
polyhedra.push_back(hPoly);
}
decomp_ros_msgs::PolyhedronArray poly_msg = DecompROS::polyhedron_array_to_ros(polyhedra);
poly_msg.header.frame_id = "world";
poly_msg.header.stamp = ros::Time::now();
publisher_map_[topic].publish(poly_msg);
}
template <class TOPIC_TYPE, class TOPIC>
void registe(const TOPIC& topic) {
auto got = publisher_map_.find(topic);
if (got == publisher_map_.end()) {
ros::Publisher pub = nh_.advertise<TOPIC_TYPE>(topic, 10);
publisher_map_[topic] = pub;
}
}
};
} // namespace visualization

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<package>
<name>tools</name>
<maintainer email="zhichaohan@zju.edu.cn">zhichaohan</maintainer>
<version>0.1.0</version>
<description> useful tools</description>
<license>GPLV3</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>nav_msgs</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>visualization_msgs</build_depend>
<build_depend>tf</build_depend>
<build_depend>cv_bridge</build_depend>
<build_depend>decomp_ros_utils</build_depend>
<run_depend>roscpp</run_depend>
<run_depend>sensor_msgs</run_depend>
<run_depend>nav_msgs</run_depend>
<run_depend>geometry_msgs</run_depend>
<run_depend>visualization_msgs</run_depend>
<run_depend>tf</run_depend>
<run_depend>cv_bridge</run_depend>
<run_depend>decomp_ros_utils</run_depend>
</package>