OOBB.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4
5#pragma GCC diagnostic push
6#pragma GCC diagnostic ignored "-Wpedantic"
7#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
8#include <CGAL/convex_hull_2.h>
9#include <CGAL/min_quadrilateral_2.h>
10#pragma GCC diagnostic pop
11
12#include <pcl/point_cloud.h>
13#include <pcl/point_types.h>
14
15#include <SimoxUtility/shapes/OrientedBox.h>
16#include <SimoxUtility/shapes/XYConstrainedOrientedBox.h>
17
20
22
23namespace armarx
24{
25 template <class ST>
28 {
29 using VectorT = Eigen::Matrix<ST, 3, 1>;
30 using MatrixT = Eigen::Matrix<ST, 3, 3>;
31
32 MatrixT mx;
33 mx.col(0) = normal.normalized();
34 const VectorT other = (mx.col(0) == VectorT::UnitZ()) ? VectorT::UnitX() : VectorT::UnitZ();
35 mx.col(1) = mx.col(0).cross(other).normalized();
36 mx.col(2) = mx.col(0).cross(mx.col(1)).normalized();
37
38 return mx;
39 }
40
41 template <class T>
43 calculate2dOOBB(const T& cloud, const Eigen::Vector3d& dir)
44 {
45 ARMARX_CHECK_GREATER(dir.norm(), 0.01) << VAROUT(dir.transpose());
46 const Eigen::Vector3d normal = dir.normalized();
47 using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
48 using Point_2 = Kernel::Point_2;
49 using Polygon_2 = CGAL::Polygon_2<Kernel>;
50
51 const Eigen::Matrix3d boxFrame = normalToRotation(normal);
52 // const Eigen::Matrix3d boxFrame = Eigen::Matrix3d::Identity();
53
54 std::vector<Point_2> allProjected;
55 double allMaxX = -std::numeric_limits<double>::infinity();
56 double allMinX = +std::numeric_limits<double>::infinity();
57 {
58 const auto& consume = [&](auto x, auto y, auto z)
59 {
60 const Eigen::Vector3d t = boxFrame.transpose() * Eigen::Vector3d{x, y, z};
61 allProjected.emplace_back(t.y(), t.z());
62 allMinX = std::min(allMinX, t.x());
63 allMaxX = std::max(allMaxX, t.x());
64 };
65 const auto& resize = [&](auto size) { allProjected.reserve(size); };
66 VisitPointLikeContainer(cloud, resize, consume);
67 }
68 ARMARX_CHECK(!allProjected.empty());
69
70 std::vector<Point_2> chullAll;
71 CGAL::convex_hull_2(allProjected.begin(), allProjected.end(), std::back_inserter(chullAll));
72
73 Polygon_2 polyAll;
74 CGAL::min_rectangle_2(chullAll.begin(), chullAll.end(), std::back_inserter(polyAll));
75 const auto& polyps = polyAll.container();
76
77 ARMARX_CHECK_EQUAL(polyps.size(), 4) << '\n'
78 << VAROUT(normal.transpose()) << '\n'
79 << VAROUT(boxFrame) << '\n'
80 << VAROUT(allProjected.size()) << '\n'
81 << VAROUT(chullAll.size()) << '\n'
82 << VAROUT(polyAll.container().size());
83
84 const auto v0 = polyps.at(0) - polyps.at(1);
85 const auto v1 = polyps.at(2) - polyps.at(1);
87 Eigen::Vector3d{allMinX, polyps.at(1).x(), polyps.at(1).y()}, //corner
88 Eigen::Vector3d{allMaxX - allMinX, 0, 0}, //v3 (in local frame it is x)
89 Eigen::Vector3d{0, v0.x(), v0.y()}, //v1
90 Eigen::Vector3d{0, v1.x(), v1.y()} //v2
91 }
92 .transformed(boxFrame);
93 }
94
95 template <class T>
96 simox::XYConstrainedOrientedBox<double>
97 calculateXYOOBB(const T& cloud)
98 {
99 const auto oobb = calculate2dOOBB(cloud, Eigen::Vector3d::UnitZ());
100 ARMARX_CHECK_GREATER(std::abs(oobb.axis_x().dot(Eigen::Vector3d::UnitZ())), 0.99)
101 << '\n'
102 << VAROUT(oobb.transformation()) << '\n'
103 << VAROUT(oobb.dimensions()) << '\n'
104 << VAROUT(oobb.axis_x().transpose());
105
106
107 const Eigen::Vector3d e1 = oobb.extend(1);
108 const Eigen::Vector3d e2 = oobb.extend(2);
109
110 return {oobb.translation(), {e1(0), e1(1)}, {e2(0), e2(1)}, oobb.dimension(0)};
111 }
112
113 template <class T>
116 {
117 const auto box1 = calculate2dOOBB(cloud, Eigen::Vector3d::UnitZ());
118
119 ARMARX_CHECK_GREATER(std::abs(box1.axis_x().normalized().dot(Eigen::Vector3d::UnitZ())),
120 0.99)
121 << '\n'
122 << VAROUT(box1.transformation());
123
124 const Eigen::Vector3d norm =
125 (box1.axis_y().norm() < box1.axis_z().norm()) ? box1.axis_y() : box1.axis_z();
126
127 const auto box2 = calculate2dOOBB(cloud, norm);
128 ARMARX_CHECK_GREATER(std::abs(box2.axis_x().normalized().dot(norm.normalized())), 0.99)
129 << '\n'
130 << VAROUT(box2.transformation()) << '\n'
131 << VAROUT(norm.transpose());
132
133 return box2;
134 }
135
136 template <class T>
137 inline std::vector<Eigen::Vector3f>
138 trimXYZHistogram(const T& cloud, const Eigen::Matrix3f& transform, const float trimEachSideBy)
139 {
140 std::vector<float> valuesX;
141 std::vector<float> valuesY;
142 std::vector<float> valuesZ;
143 std::size_t sz = 0;
144 {
145 const auto& consume = [&](auto x, auto y, auto z)
146 {
147 const Eigen::Vector3f ted = transform * Eigen::Vector3f{x, y, z};
148 valuesX.emplace_back(ted.x());
149 valuesY.emplace_back(ted.y());
150 valuesZ.emplace_back(ted.z());
151 };
152 const auto& resize = [&](auto size)
153 {
154 sz = size;
155 valuesX.reserve(size);
156 valuesY.reserve(size);
157 valuesZ.reserve(size);
158 };
159 VisitPointLikeContainer(cloud, resize, consume);
160 }
161
162 std::sort(valuesX.begin(), valuesX.end());
163 std::sort(valuesY.begin(), valuesY.end());
164 std::sort(valuesZ.begin(), valuesZ.end());
165
166 const std::size_t idxLo = sz * trimEachSideBy;
167 const std::size_t idxHi = sz - std::max(idxLo, 1ul);
168 const float loX = valuesX.at(idxLo);
169 const float hiX = valuesX.at(idxHi);
170 const float loY = valuesY.at(idxLo);
171 const float hiY = valuesY.at(idxHi);
172 const float loZ = valuesZ.at(idxLo);
173 const float hiZ = valuesZ.at(idxHi);
174
175
176 std::vector<Eigen::Vector3f> result;
177 {
178 const auto& consume = [&](auto x, auto y, auto z)
179 {
180 const Eigen::Vector3f ted = transform * Eigen::Vector3f{x, y, z};
181 if (ted.x() <= hiX && ted.x() >= loX && ted.y() <= hiY && ted.y() >= loY &&
182 ted.z() <= hiZ && ted.z() >= loZ)
183 {
184 result.emplace_back(x, y, z);
185 }
186 };
187 const auto& resize = [&](auto) {};
188 VisitPointLikeContainer(cloud, resize, consume);
189 }
190
191 return result;
192 }
193
194} // namespace armarx
#define VAROUT(x)
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
This file offers overloads of toIce() and fromIce() functions for STL container types.
Eigen::Matrix< ST, 3, 3 > normalToRotation(const Eigen::Matrix< ST, 3, 1 > &normal)
Definition OOBB.hpp:27
simox::XYConstrainedOrientedBox< double > calculateXYOOBB(const T &cloud)
Definition OOBB.hpp:97
std::vector< Eigen::Vector3f > trimXYZHistogram(const T &cloud, const Eigen::Matrix3f &transform, const float trimEachSideBy)
Definition OOBB.hpp:138
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT > >
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition algorithm.h:351
void VisitPointLikeContainer(const auto &cloud, auto &&perElem, auto &&sizeInfo)
simox::OrientedBox< float > calculate2dOOBB(const std::vector< Eigen::Vector3f > &points, const Eigen::Vector3f &dir)
Definition OOBB.cpp:6
simox::OrientedBox< double > calculateDouble2dOOBB(const T &cloud)
Definition OOBB.hpp:115
double norm(const Point &a)
Definition point.hpp:102