forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpoint_cloud_flags.h
201 lines (165 loc) · 6.03 KB
/
point_cloud_flags.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#pragma once
#include <iostream>
#include <stdexcept>
#include <string>
#include "drake/common/drake_assert.h"
#include "drake/common/drake_copyable.h"
namespace drake {
namespace perception {
/// Point cloud flags.
namespace pc_flags {
typedef int BaseFieldT;
/// Indicates the data the point cloud stores.
enum BaseField : int {
kNone = 0,
/// Inherit other fields. May imply an intersection of all
/// compatible descriptors.
kInherit = 1 << 0,
/// XYZ point in Cartesian space.
kXYZs = 1 << 1,
/// Normals.
kNormals = 1 << 2,
/// RGB colors.
kRGBs = 1 << 3,
};
namespace internal {
// N.B. Ensure this is the largest bit.
constexpr BaseField kMaxBitInUse = kRGBs;
} // namespace internal
/// Describes an descriptor field with a name and the descriptor's size.
///
/// @note This is defined as follows to enable an open set of descriptors, but
/// ensure that these descriptor types are appropriately matched.
/// As `PointCloud` evolves and more algorithms are mapped into Drake,
/// promoting an descriptor field to a proper field should be considered if (a)
/// it is used frequently enough AND (b) if it is often used in conjunction
/// with other fields.
class DescriptorType final {
public:
DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(DescriptorType)
constexpr DescriptorType(int size, const char* name)
: size_(size),
name_(name) {}
inline int size() const { return size_; }
inline std::string name() const { return name_; }
inline bool operator==(const DescriptorType& other) const {
return size_ == other.size_ && name() == other.name();
}
inline bool operator!=(const DescriptorType& other) const {
return !(*this == other);
}
private:
int size_{};
const char* name_{nullptr};
};
/// No descriptor.
constexpr DescriptorType kDescriptorNone(0, "kDescriptorNone");
/// Curvature.
constexpr DescriptorType kDescriptorCurvature(1, "kDescriptorCurvature");
/// Point-feature-histogram.
constexpr DescriptorType kDescriptorFPFH(33, "kDescriptorFPFH");
/**
* Allows combination of `BaseField` and `DescriptorType` for a `PointCloud`.
* You may combine multiple `BaseField`s, but you may have only zero or one
* `DescriptorType`.
*
* This provides the mechanism to use basic bit-mask operators (| &) to
* combine / intersect fields for convenience.
*/
class Fields {
public:
DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(Fields)
/// @throws std::runtime_error if `base_fields` is not composed of valid
/// `BaseField`s.
Fields(BaseFieldT base_fields, DescriptorType descriptor_type)
: base_fields_(base_fields),
descriptor_type_(descriptor_type) {}
/// @throws std::runtime_error if `base_fields` is not composed of valid
/// `BaseField`s.
Fields(BaseFieldT base_fields) // NOLINT(runtime/explicit)
: base_fields_(base_fields) {
if (base_fields < 0 || base_fields >= (internal::kMaxBitInUse << 1))
throw std::runtime_error("Invalid BaseField specified.");
}
// NOLINTNEXTLINE(runtime/explicit): This conversion is desirable.
Fields(const DescriptorType& descriptor_type)
: descriptor_type_(descriptor_type) {}
/// Returns the contained base fields.
BaseFieldT base_fields() const { return base_fields_; }
/// Returns whether there are any base fields contained by this set of fields.
bool has_base_fields() const {
return base_fields_ != kNone;
}
/// Returns the contained descriptor type.
const DescriptorType& descriptor_type() const { return descriptor_type_; }
/// Returns whether there is a descriptor contained by this set of fields.
bool has_descriptor() const {
return descriptor_type_ != kDescriptorNone;
}
/// Provides in-place union.
/// @throws std::runtime_error if multiple non-None `DescriptorType`s are
/// specified.
Fields& operator|=(const Fields& rhs) {
base_fields_ = base_fields_ | rhs.base_fields_;
if (has_descriptor())
throw std::runtime_error(
"Cannot have multiple Descriptor flags. "
"Can only add flags iff (!rhs.has_descriptor()).");
descriptor_type_ = rhs.descriptor_type_;
return *this;
}
/// Provides union.
/// @see operator|= for preconditions.
Fields operator|(const Fields& rhs) const {
return Fields(*this) |= rhs;
}
/// Provides in-place intersection.
Fields& operator&=(const Fields& rhs) {
base_fields_ &= rhs.base_fields_;
if (descriptor_type_ != rhs.descriptor_type_) {
descriptor_type_ = kDescriptorNone;
}
return *this;
}
/// Provides intersection.
Fields operator&(const Fields& rhs) const {
return Fields(*this) &= rhs;
}
/// Returns whether both value types (BaseField + DescriptorType) are none.
bool empty() const {
return !has_base_fields() && !has_descriptor();
}
/// Returns whether this set of fields contains (is a superset of) `rhs`.
bool contains(const Fields& rhs) const {
return (*this & rhs) == rhs;
}
bool operator==(const Fields& rhs) const {
return (base_fields_ == rhs.base_fields_
&& descriptor_type_ == rhs.descriptor_type_);
}
bool operator!=(const Fields& rhs) const {
return !(*this == rhs);
}
/// Provides human-readable output.
friend std::ostream& operator<<(std::ostream& os, const Fields& rhs);
private:
// TODO(eric.cousineau): Use `optional` to avoid the need for `none` objects?
BaseFieldT base_fields_{kNone};
DescriptorType descriptor_type_{kDescriptorNone};
};
// Do not use implicit conversion because it becomes ambiguous.
/// Makes operator| compatible for `BaseField` + `DescriptorType`.
/// @see Fields::operator|= for preconditions.
inline Fields operator|(const BaseFieldT& lhs, const DescriptorType& rhs) {
return Fields(lhs) | Fields(rhs);
}
/// Makes operator| compatible for `DescriptorType` + `Fields`
/// (`DescriptorType` or `BaseFields`).
/// @see Fields::operator|= for preconditions.
inline Fields operator|(const DescriptorType& lhs, const Fields& rhs) {
return Fields(lhs) | rhs;
}
// TODO(eric.cousineau): Add compatible operator& if the need arises.
} // namespace pc_flags
} // namespace perception
} // namespace drake