-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
rotation_constraint_visualization.cc
154 lines (148 loc) · 6.42 KB
/
rotation_constraint_visualization.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "drake/solvers/test/rotation_constraint_visualization.h"
#include "drake/common/proto/call_python.h"
#include "drake/solvers/mixed_integer_rotation_constraint.h"
#include "drake/solvers/mixed_integer_rotation_constraint_internal.h"
#include "drake/solvers/rotation_constraint.h"
namespace drake {
namespace solvers {
namespace {
// Draw an arc between two end points on the unit sphere. The two end points
// are the vertices of the intersection region, between the box and the surface
// of the sphere.
// This requires that
// arc_end0(fixed_axis) = arc_end1(fixed_axis) = x(fixed_axis),
// where `x` is a point on the arc.
// Draws the shorter arc between the two points.
void DrawArcBoundaryOfBoxSphereIntersection(const Eigen::Vector3d& arc_end0,
const Eigen::Vector3d& arc_end1,
int fixed_axis,
const Eigen::RowVector3d& color) {
DRAKE_DEMAND(std::abs(arc_end0(fixed_axis) - arc_end1(fixed_axis)) < 1E-3);
DRAKE_DEMAND(std::abs(arc_end0.norm() - 1) < 1E-3);
DRAKE_DEMAND(std::abs(arc_end1.norm() - 1) < 1E-3);
int free_axis0 = (fixed_axis + 1) % 3;
int free_axis1 = (fixed_axis + 2) % 3;
if (arc_end0(free_axis0) * arc_end1(free_axis0) < 0 ||
arc_end0(free_axis1) * arc_end1(free_axis1) < 0) {
// The two end points have to be in the same orthant.
throw std::runtime_error(
"The end points of the boundary arc are not in the same orthant.");
}
const int kNumViaPoints = 20;
Eigen::Matrix<double, 3, kNumViaPoints> via_pts;
via_pts.row(fixed_axis) =
Eigen::Matrix<double, 1, kNumViaPoints>::Constant(arc_end0(fixed_axis));
Eigen::Vector3d start_via_pts, end_via_pts;
// Eigen::LinSpaced requires the smaller number being the first argument. So
// find out whether arc_end0(free_axis0) or arc_end1(free_axis0) is smaller.
if (arc_end0(free_axis0) < arc_end1(free_axis0)) {
start_via_pts = arc_end0;
end_via_pts = arc_end1;
} else {
start_via_pts = arc_end1;
end_via_pts = arc_end0;
}
via_pts.row(free_axis0) = Eigen::Matrix<double, 1, kNumViaPoints>::LinSpaced(
kNumViaPoints, start_via_pts(free_axis0), end_via_pts(free_axis0));
via_pts(free_axis1, 0) = start_via_pts(free_axis1);
via_pts(free_axis1, kNumViaPoints - 1) = end_via_pts(free_axis1);
bool positive_free_axis1 =
arc_end0(free_axis1) > 0 || arc_end1(free_axis1) > 0;
for (int i = 1; i < kNumViaPoints - 1; ++i) {
// A point `x` on the arc satisfies
// x(free_axis0)^2 + x(free_axis1)^2 = 1 - x(fixed_axis)^2
via_pts(free_axis1, i) = std::sqrt(1 - std::pow(via_pts(fixed_axis, i), 2) -
std::pow(via_pts(free_axis0, i), 2));
if (!positive_free_axis1) {
via_pts(free_axis1, i) *= -1;
}
}
using common::CallPython;
using common::ToPythonKwargs;
CallPython("plot3", via_pts.row(0).transpose(), via_pts.row(1).transpose(),
via_pts.row(2).transpose(),
ToPythonKwargs("color", color.transpose()));
}
} // namespace
void DrawSphere(const Eigen::RowVector3d& color) {
using common::CallPython;
using common::ToPythonKwargs;
CallPython("sphere", 40,
ToPythonKwargs("alpha", 0.2, "color", color.transpose(),
"linestyle", "None"));
}
void DrawBox(const Eigen::Vector3d& bmin, const Eigen::Vector3d& bmax,
const Eigen::RowVector3d& color) {
using common::CallPython;
using common::ToPythonKwargs;
if ((bmin.array() < 0).any()) {
throw std::runtime_error("bmin should be in the first orthant in DrawBox.");
}
if ((bmax.array() < 0).any()) {
throw std::runtime_error("bmax should be in the first orthant in DrawBox.");
}
if (bmin.norm() <= 1 && bmax.norm() >= 1) {
// The box and the sphere has intersections.
CallPython("box", bmin, bmax,
ToPythonKwargs("alpha", 0.2, "color", color.transpose(),
"linestyle", "None"));
}
}
void DrawBoxSphereIntersection(const Eigen::Vector3d& bmin,
const Eigen::Vector3d& bmax,
const Eigen::RowVector3d& color) {
DRAKE_DEMAND((bmax.array() > bmin.array()).all());
// First convert bmin and bmax to the first orthant.
Eigen::Vector3d orthant_bmin;
Eigen::Vector3d orthant_bmax;
// orthant_sign(i) = 1 if the i'th axis of the box is positive, otherwise it
// is -1.
Eigen::Vector3i orthant_sign;
for (int i = 0; i < 3; ++i) {
if (bmin(i) >= 0) {
orthant_bmin(i) = bmin(i);
orthant_bmax(i) = bmax(i);
orthant_sign(i) = 1;
} else if (bmax(i) <= 0) {
orthant_bmin(i) = -bmax(i);
orthant_bmax(i) = -bmin(i);
orthant_sign(i) = -1;
} else {
throw std::runtime_error(
"The box bmin <= x <= bmax should satisfy either bmin(i) >=0 or "
"bmax(i) <= 0");
}
}
// Compute the intersection points between the sphere in the first orthant,
// with the box orthant_bmin <= x <= orthant_bmax
auto intersection_pts = internal::ComputeBoxEdgesAndSphereIntersection(
orthant_bmin, orthant_bmax);
// Now convert the intersection point back to the right orthant.
for (int i = 0; i < static_cast<int>(intersection_pts.size()); ++i) {
for (int j = 0; j < 3; ++j) {
intersection_pts[i](j) *= orthant_sign(j);
}
}
// Draw the line that connects adjacent intersection points.
// For each intersection point, find out the neighbouring points, and then
// draw the arc between these two points. The neighbouring points should have
// one axis same as the queried intersection point. Also, the neighbouring
// points should be on the facet of the box as the queried intersection point.
for (int i = 0; i < static_cast<int>(intersection_pts.size()); ++i) {
for (int j = i + 1; j < static_cast<int>(intersection_pts.size()); ++j) {
for (int dim = 0; dim < 3; ++dim) {
if (std::abs(intersection_pts[i](dim) - intersection_pts[j](dim)) <
1E-3 &&
(std::abs(intersection_pts[i](dim) - bmin(dim)) < 1E-3 ||
std::abs(intersection_pts[i](dim) - bmax(dim)) < 1E-3)) {
// Determine if two intersection points are the neighbouring boundary
// points of the intersection region.
DrawArcBoundaryOfBoxSphereIntersection(
intersection_pts[i], intersection_pts[j], dim, color);
}
}
}
}
}
} // namespace solvers
} // namespace drake