Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixup! Use a function pointer for cloning #41

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions geometry/optimization/convex_set.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,26 @@ using solvers::VectorXDecisionVariable;
using std::pair;
using std::sqrt;

ConvexSet::ConvexSet(
std::function<std::unique_ptr<ConvexSet>(const ConvexSet&)> cloner,
int ambient_dimension)
: cloner_(std::move(cloner)),
ambient_dimension_(ambient_dimension) {
DRAKE_DEMAND(ambient_dimension >= 0);
}

std::unique_ptr<ConvexSet> ConvexSet::Clone() const { return cloner_(*this); }

HPolyhedron::HPolyhedron(const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::VectorXd>& b)
: ConvexSet(ConvexSetTag<HPolyhedron>(), A.cols()), A_{A}, b_{b} {
: ConvexSet(&ConvexSetCloner<HPolyhedron>, A.cols()), A_{A}, b_{b} {
DRAKE_DEMAND(A.rows() == b.size());
}

HPolyhedron::HPolyhedron(const QueryObject<double>& query_object,
GeometryId geometry_id,
std::optional<FrameId> expressed_in)
: ConvexSet(ConvexSetTag<HPolyhedron>(), 3) {
: ConvexSet(&ConvexSetCloner<HPolyhedron>, 3) {
std::pair<Eigen::MatrixXd, Eigen::VectorXd> Ab_G;
query_object.inspector().GetShape(geometry_id).Reify(this, &Ab_G);

Expand Down Expand Up @@ -134,7 +142,7 @@ void HPolyhedron::ImplementGeometry(const Box& box, void* data) {

HyperEllipsoid::HyperEllipsoid(const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::VectorXd>& center)
: ConvexSet(ConvexSetTag<HyperEllipsoid>(), center.size()),
: ConvexSet(&ConvexSetCloner<HyperEllipsoid>, center.size()),
A_{A},
center_{center} {
DRAKE_DEMAND(A.rows() == center.size());
Expand All @@ -143,7 +151,7 @@ HyperEllipsoid::HyperEllipsoid(const Eigen::Ref<const Eigen::MatrixXd>& A,
HyperEllipsoid::HyperEllipsoid(const QueryObject<double>& query_object,
GeometryId geometry_id,
std::optional<FrameId> expressed_in)
: ConvexSet(ConvexSetTag<HyperEllipsoid>(), 3) {
: ConvexSet(&ConvexSetCloner<HyperEllipsoid>, 3) {
Eigen::Matrix3d A_G;
query_object.inspector().GetShape(geometry_id).Reify(this, &A_G);
// p_GG_varᵀ * A_Gᵀ * A_G * p_GG_var ≤ 1
Expand Down
50 changes: 24 additions & 26 deletions geometry/optimization/convex_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <optional>
#include <utility>

#include "drake/common/drake_assert.h"
#include "drake/geometry/geometry_ids.h"
#include "drake/geometry/query_object.h"
#include "drake/geometry/shape_specification.h"
Expand Down Expand Up @@ -54,12 +55,6 @@ The geometry::optimization tools support:
@ingroup solvers
*/

/** Simple struct for instantiating the type-specific ConvexSet functionality.
A class derived from the ConvexSet class will invoke the parent's constructor
as ConvexSet(ConvexSetTag<DerivedSet>()). */
template <typename S>
struct ConvexSetTag{};

/** Abstract base class for defining a convex set.
@ingroup geometry_optimization
*/
Expand Down Expand Up @@ -109,29 +104,21 @@ class ConvexSet : public ShapeReifier {
protected:
DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(ConvexSet)

/** A derived class should invoke this with e.g.:
```
/** For use by derived classes to construct a %ConvexSet.

@param cloner Function pointer to implement Clone(), typically of the form
`&ConvexSetCloner<Derived>`.

Here is a typical example:
@code
class MyConvexSet final : public ConvexSet {
public:
MyConvexSet() : ConvexSet(ConvexSetTag<MyConvexSet>()) {}
MyConvexSet() : ConvexSet(&ConvexSetCloner<MyConvexSet>, 3) {}
...
};
```
*/
template <typename S>
ConvexSet(ConvexSetTag<S>, int ambient_dimension)
: ambient_dimension_{ambient_dimension} {
static_assert(std::is_base_of_v<ConvexSet, S>,
"Concrete sets *must* be derived from the ConvexSet class");

DRAKE_DEMAND(ambient_dimension >= 0);

cloner_ = [](const ConvexSet& set) {
DRAKE_DEMAND(typeid(set) == typeid(S));
const S& derived_set = static_cast<const S&>(set);
return std::unique_ptr<ConvexSet>(new S(derived_set));
};
}
@endcode */
ConvexSet(std::function<std::unique_ptr<ConvexSet>(const ConvexSet&)> cloner,
int ambient_dimension);

// Non-virtual interface implementations.
virtual bool DoPointInSet(const Eigen::Ref<const Eigen::VectorXd>& x,
Expand All @@ -144,10 +131,21 @@ class ConvexSet : public ShapeReifier {
virtual std::pair<std::unique_ptr<Shape>, math::RigidTransformd>
DoToShapeWithPose() const = 0;

int ambient_dimension_{0};
std::function<std::unique_ptr<ConvexSet>(const ConvexSet&)> cloner_;
int ambient_dimension_{0};
};

/** (Advanced) Implementation helper for ConvexSet::Clone. Refer to the
ConvexSet::ConvexSet() constructor documentation for an example. */
template <typename Derived>
std::unique_ptr<ConvexSet> ConvexSetCloner(const ConvexSet& other) {
static_assert(std::is_base_of_v<ConvexSet, Derived>,
"Concrete sets *must* be derived from the ConvexSet class");
DRAKE_DEMAND(typeid(other) == typeid(Derived));
const auto& typed_other = static_cast<const Derived&>(other);
return std::make_unique<Derived>(typed_other);
}

// Forward declaration.
class HyperEllipsoid;

Expand Down