-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
proximity_utilities.h
166 lines (131 loc) · 6.27 KB
/
proximity_utilities.h
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
155
156
157
158
159
160
161
162
163
164
165
166
#pragma once
#include <algorithm>
#include <cstdint>
#include <string>
#include <vector>
#include <fcl/fcl.h>
#include <fmt/format.h>
#include "drake/geometry/geometry_ids.h"
#include "drake/geometry/proximity/volume_mesh.h"
#include "drake/geometry/shape_specification.h"
namespace drake {
namespace geometry {
namespace internal {
// TODO(SeanCurtis-TRI): Given the dependencies on fcl for this file, the name
// should reflect it so that it doesn't get included in files that will
// eventually get included in the public API.
// TODO(SeanCurtis-TRI): Snake case this name.
/* Calculates an absolute tolerance value conditioned to a problem's
characteristic, positive-valued `size`. The tolerance is sufficient to account
for round-off error which arises due to transformations.
@pre size > 0. */
constexpr double DistanceToPointRelativeTolerance(double size) {
return 1e-14 * std::max(1.0, size);
}
/* Class for coordinating the collision objects stored in the proximity engine
with the geometries stored in SceneGraph. The two are related in that the
collision object stores the GeometryId of the corresponding SceneGraph
geometry as well as a bit to mark whether it is anchored or dynamic.
It stores this data by compactly "encoding" them. The encoding packs a geometry
id value with a bit indicating if the id refers to dynamic or anchored geometry
(proximity engine segregates them). The highest-order bit indicates dynamic (1)
or anchored (0). The remaining lower bits store the id. The data is stored in a
pointer-sized integer. This integer is, in turn, stored directly into
fcl::CollisionObject's void* user data member. */
class EncodedData {
public:
using ValueType = decltype(GeometryId::get_new_id().get_value());
/* Constructs encoded data directly from the id and the known
anchored/dynamic characterization. */
EncodedData(GeometryId id, bool is_dynamic)
: data_(static_cast<ValueType>(id.get_value())) {
// Make sure we haven't used so many ids that we're *using* the highest-
// order bit -- i.e., it must be strictly positive.
DRAKE_DEMAND(data_ > 0);
if (is_dynamic) set_dynamic();
// NOTE: data is encoded as anchored by default. So, an action only needs to
// be taken in the dynamic case.
}
/* Constructs encoded data by extracting it from the given collision object.
*/
explicit EncodedData(const fcl::CollisionObject<double>& fcl_object)
: data_(reinterpret_cast<ValueType>(fcl_object.getUserData())) {}
/* Constructs encoded data for the given id identified as dynamic. */
static EncodedData encode_dynamic(GeometryId id) {
return {id, true};
}
/* Constructs encoded data for the given id identified as anchored. */
static EncodedData encode_anchored(GeometryId id) {
return {id, false};
}
/* Sets the encoded data to be dynamic. */
void set_dynamic() { data_ |= kIsDynamicMask; }
/* Sets the encoded data to be anchored. */
void set_anchored() { data_ &= ~kIsDynamicMask; }
/* Writes the encoded data into the collision object's user data. */
void write_to(fcl::CollisionObject<double>* object) const {
object->setUserData(reinterpret_cast<void*>(data_));
}
/* Reports true if the encoded data is marked as dynamic. False if anchored.
*/
bool is_dynamic() const { return (data_ & kIsDynamicMask) != 0; }
/* Reports the stored id. */
GeometryId id() const {
return static_cast<GeometryId>(data_ & ~kIsDynamicMask);
}
/* Reports the encoded data. */
ValueType encoding() const { return data_; }
private:
// For this encoding to work we have the following requirements:
// 1. ValueType must be at least as large as a pointer.
// 2. ValueType must be at least as large as GeometryId. (At least as large
// still implies that with enough GeometryIds allocated, the high order
// bit could become ambiguous -- however, that would require one id for
// each atom in the universe).
// These static asserts guarantee these conditions.
// This is redundant of the declaration of ValueType; it serves as an
// independent witness to the requirement in case the declaration changes.
static_assert(sizeof(ValueType) >= sizeof(GeometryId),
"The encoded data type must be at least as large as the "
"identifier to use in EncodedData");
static_assert(sizeof(ValueType) >= sizeof(void*),
"The encoded data type must be at least as large as a pointer "
"type");
// Regardless of how large ValueType is, ultimately, we need to be able to
// pack the encoding into a void*. So, we set the bit mask as the highest
// order bit of something pointer sized.
static const ValueType kIsDynamicMask = ValueType{1}
<< (sizeof(void*) * 8 - 1);
// The encoded data - id and mobility type masked together.
ValueType data_{};
};
/* Returns the name of the geometry associated with the given collision
`object`. */
std::string GetGeometryName(const fcl::CollisionObjectd& object);
// TODO(joemasterjohn): Move the below mesh testing utilities to a separate
// target only used by tests.
/* Counts the unique 1-simplices (edges) in `mesh`. */
int CountEdges(const VolumeMesh<double>& mesh);
/* Counts the unique 2-simplices (faces) in the `mesh` */
int CountFaces(const VolumeMesh<double>& mesh);
/*
Computes the generalized Euler characteristic:
χ = k₀ - k₁ + k₂ - k₃
Where kᵢ is the number of i-simplexes in the mesh.
We can use χ in a necessary condition for a _conforming_
tetrahedral mesh (any two tetrahedra intersect in their shared
face, or shared edge, or shared vertex, or not at all. There is
no partial overlapping of two tetrahedra.).
For example, every tetrahedral mesh of every geometric primitive
(Box , Cylinder, Ellipsoid, Sphere, etc.) must have χ = 1 because
it is topologically equivalent to a solid ball.
*/
int ComputeEulerCharacteristic(const VolumeMesh<double>& mesh);
using Eigen::Vector3d;
/* Computes the signed distance to the capsule's surface from point P. The point
is measured and expressed in the capsule's canonical frame C. Negative values
for points *inside* the capsule, positive value for points outside. */
double CalcDistanceToSurface(const Capsule& capsule, const Vector3d& p_CP);
} // namespace internal
} // namespace geometry
} // namespace drake