2
2
3
3
#include < memory>
4
4
#include < string>
5
+ #include < variant>
5
6
6
7
#include " drake/common/drake_copyable.h"
7
8
#include " drake/common/drake_deprecated.h"
@@ -36,16 +37,15 @@ class Sphere;
36
37
//
37
38
// When you add a new subclass of Shape to Drake, you must:
38
39
//
39
- // 1. Add a virtual function ImplementGeometry() for the new shape in
40
+ // 1. Adjust the VariantShapeConstPtr typedef to list the new subclass.
41
+ //
42
+ // 2. Add a virtual function ImplementGeometry() for the new shape in
40
43
// ShapeReifier that invokes the ThrowUnsupportedGeometry method, and add to
41
44
// the test for it in shape_specification_test.cc.
42
45
//
43
- // 2. Implement ImplementGeometry in derived ShapeReifiers to continue support
44
- // if desired, otherwise ensure unimplemented functions are not hidden in new
45
- // derivations of ShapeReifier with `using`, for example, `using
46
- // ShapeReifier::ImplementGeometry`. Existing subclasses should already have
47
- // this. Otherwise, you might get a runtime error; we do not have an
48
- // automatic way to enforce them at compile time.
46
+ // 3. Grep Drake for the line `using ShapeReifier::ImplementGeometry;` (a trick
47
+ // that selects a default-throw implementation) and choose which (if any) of
48
+ // those reifiers you want to add support for this new shape into.
49
49
50
50
/* * The abstract base class for all shape specifications. Concrete subclasses
51
51
exist for specific shapes (e.g., Box, Mesh, etc.).
@@ -76,6 +76,33 @@ class Shape {
76
76
/* * Returns a string representation of this shape. */
77
77
std::string to_string () const { return do_to_string (); }
78
78
79
+ /* * Calls the given `visitor` function with `*this` as the sole argument, but
80
+ with `*this` downcast to be the shape's concrete subclass. For example, if
81
+ this shape is a %Box then calls `visitor(static_cast<const Box&>(*this))`.
82
+ @tparam ReturnType The return type to coerce return values into. When not
83
+ `void`, anything returned by the visitor must be implicitly convertible to
84
+ this type. When `void`, the return type will be whatever the Vistor's call
85
+ operator returns by default.
86
+
87
+ To see examples of how this is used, you can check the Drake source code,
88
+ e.g., check the implementation of CalcVolume() for one example. */
89
+ template <typename ReturnType = void , typename Visitor>
90
+ decltype (auto ) Visit(Visitor&& visitor) const {
91
+ if constexpr (std::is_same_v<ReturnType, void >) {
92
+ return std::visit (
93
+ [&visitor](auto * shape) {
94
+ return visitor (*shape);
95
+ },
96
+ get_variant_this ());
97
+ } else {
98
+ return std::visit (
99
+ [&visitor](auto * shape) -> ReturnType {
100
+ return visitor (*shape);
101
+ },
102
+ get_variant_this ());
103
+ }
104
+ }
105
+
79
106
protected:
80
107
/* * (Internal use only) Constructor for use by derived classes.
81
108
All subclasses of Shape must be marked `final`. */
@@ -102,6 +129,21 @@ class Shape {
102
129
103
130
/* * (Internal use only) NVI for to_string(). */
104
131
virtual std::string do_to_string () const = 0;
132
+
133
+ /* * (Internal use only) All concrete subclasses, as const pointers. */
134
+ using VariantShapeConstPtr = std::variant< //
135
+ const Box*, //
136
+ const Capsule*, //
137
+ const Convex*, //
138
+ const Cylinder*, //
139
+ const Ellipsoid*, //
140
+ const HalfSpace*, //
141
+ const Mesh*, //
142
+ const MeshcatCone*, //
143
+ const Sphere*>;
144
+
145
+ /* * (Internal use only) NVI-like helper function for Visit(). */
146
+ virtual VariantShapeConstPtr get_variant_this () const = 0;
105
147
};
106
148
107
149
/* * Definition of a box. The box is centered on the origin of its canonical
@@ -146,6 +188,7 @@ class Box final : public Shape {
146
188
std::unique_ptr<Shape> DoClone () const final ;
147
189
std::string_view do_type_name () const final ;
148
190
std::string do_to_string () const final ;
191
+ VariantShapeConstPtr get_variant_this () const final ;
149
192
150
193
Vector3<double > size_;
151
194
};
@@ -180,6 +223,7 @@ class Capsule final : public Shape {
180
223
std::unique_ptr<Shape> DoClone () const final ;
181
224
std::string_view do_type_name () const final ;
182
225
std::string do_to_string () const final ;
226
+ VariantShapeConstPtr get_variant_this () const final ;
183
227
184
228
double radius_{};
185
229
double length_{};
@@ -246,6 +290,7 @@ class Convex final : public Shape {
246
290
std::unique_ptr<Shape> DoClone () const final ;
247
291
std::string_view do_type_name () const final ;
248
292
std::string do_to_string () const final ;
293
+ VariantShapeConstPtr get_variant_this () const final ;
249
294
250
295
std::string filename_;
251
296
std::string extension_;
@@ -279,6 +324,7 @@ class Cylinder final : public Shape {
279
324
std::unique_ptr<Shape> DoClone () const final ;
280
325
std::string_view do_type_name () const final ;
281
326
std::string do_to_string () const final ;
327
+ VariantShapeConstPtr get_variant_this () const final ;
282
328
283
329
double radius_{};
284
330
double length_{};
@@ -321,6 +367,7 @@ class Ellipsoid final : public Shape {
321
367
std::unique_ptr<Shape> DoClone () const final ;
322
368
std::string_view do_type_name () const final ;
323
369
std::string do_to_string () const final ;
370
+ VariantShapeConstPtr get_variant_this () const final ;
324
371
325
372
Vector3<double > radii_;
326
373
};
@@ -361,6 +408,7 @@ class HalfSpace final : public Shape {
361
408
std::unique_ptr<Shape> DoClone () const final ;
362
409
std::string_view do_type_name () const final ;
363
410
std::string do_to_string () const final ;
411
+ VariantShapeConstPtr get_variant_this () const final ;
364
412
};
365
413
366
414
// TODO(DamrongGuoy): Update documentation when mesh is fully supported (i.e.,
@@ -440,6 +488,7 @@ class Mesh final : public Shape {
440
488
std::unique_ptr<Shape> DoClone () const final ;
441
489
std::string_view do_type_name () const final ;
442
490
std::string do_to_string () const final ;
491
+ VariantShapeConstPtr get_variant_this () const final ;
443
492
444
493
// NOTE: Cannot be const to support default copy/move semantics.
445
494
std::string filename_;
@@ -488,6 +537,7 @@ class MeshcatCone final : public Shape {
488
537
std::unique_ptr<Shape> DoClone () const final ;
489
538
std::string_view do_type_name () const final ;
490
539
std::string do_to_string () const final ;
540
+ VariantShapeConstPtr get_variant_this () const final ;
491
541
492
542
double height_{};
493
543
double a_{};
@@ -514,6 +564,7 @@ class Sphere final : public Shape {
514
564
std::unique_ptr<Shape> DoClone () const final ;
515
565
std::string_view do_type_name () const final ;
516
566
std::string do_to_string () const final ;
567
+ VariantShapeConstPtr get_variant_this () const final ;
517
568
518
569
double radius_{};
519
570
};
0 commit comments