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

Add support for merge-include in the Interface API #768

Merged
merged 28 commits into from Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6da93ae
Refactor FrameSemantics.cc
azeey Nov 30, 2021
d11402a
Merge branch 'sdf12' into refactor_frame_semantics
scpeters Dec 1, 2021
867422a
Merge remote-tracking branch 'upstream/sdf12' into refactor_frame_sem…
azeey Dec 1, 2021
a46517a
Fix MSVC compiler warnings
azeey Dec 1, 2021
f2b2f47
Reviewer feedback
azeey Dec 1, 2021
56d7216
Merge branch 'sdf12' into refactor_frame_semantics
scpeters Dec 2, 2021
e9507ad
Add support for merge-include in the Interface API
azeey Dec 2, 2021
addddb9
Handle placement frames
azeey Dec 2, 2021
f3b0f93
Use wrappers to create a common API on regular DOM objects and interf…
azeey Dec 3, 2021
f805d0b
Merge remote-tracking branch 'upstream/sdf12' into refactor_frame_sem…
azeey Dec 14, 2021
5b5c171
Change name of helper build*Graph function
azeey Dec 14, 2021
bdbd692
Merge branch 'refactor_frame_semantics' into merge_include_interface_api
azeey Dec 14, 2021
db4319e
Use new reworked refactor code for merge include
azeey Dec 15, 2021
3ec800e
Fix style, rename buildPoseRelativeToGraph to wrapperBuildPoseRelativ…
azeey Dec 15, 2021
97d8293
Merge branch 'refactor_frame_semantics' into merge_include_interface_api
azeey Dec 15, 2021
1f9df5f
Style, documentation
azeey Dec 15, 2021
1eaf118
Merge remote-tracking branch 'upstream/sdf12' into merge_include_inte…
azeey Jan 11, 2022
1818729
Add comments
azeey Jan 11, 2022
399340c
Fix test and compiler warning
azeey Jan 20, 2022
a56a773
Merge remote-tracking branch 'upstream/sdf12' into merge_include_inte…
azeey Jan 20, 2022
09b6421
Verify that //joint/child cannot be __model__
azeey Jan 20, 2022
1907e5d
Change ParserSupportsMergeInclude to bool, address reviewer feedback
azeey Jan 20, 2022
c778b71
Merge branch 'sdf12' into merge_include_interface_api
azeey Jan 24, 2022
2ec9e98
Merge remote-tracking branch 'upstream/sdf12' into merge_include_inte…
azeey Jan 28, 2022
2d16a82
Revert "Verify that //joint/child cannot be __model__"
azeey Jan 27, 2022
1991fbf
Handle __model__ as //joint/child in merge included interface joint
azeey Jan 27, 2022
74f06b7
Remove unused header
azeey Jan 28, 2022
60708f0
Address reviewer feedback
azeey Feb 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/sdf/Error.hh
Expand Up @@ -145,7 +145,7 @@ namespace sdf
VERSION_DEPRECATED,

/// \brief Merge include is unspported for the type of entity being
/// included.
/// included, or the custom parser does not support merge includes.
MERGE_INCLUDE_UNSUPPORTED,
};

Expand Down
11 changes: 11 additions & 0 deletions include/sdf/InterfaceElements.hh
Expand Up @@ -154,6 +154,17 @@ class SDFORMAT_VISIBLE NestedInclude
/// \param[in] _includeElement The include element
public: void SetIncludeElement(sdf::ElementPtr _includeElement);


/// \brief Set whether the interface model is to be merge-included (i.e
/// set the value of `//include/[@merge]`)
/// \param[in] _isMerge True if the interface model is to be merge included
public: void SetIsMerge(bool _isMerge);

/// \brief Whether the interface model is to be merge-included
/// \return If `//include/[@merge]` is set, this returns the value of the
/// attribute, otherwise, nullopt.
public: const std::optional<bool> &IsMerge() const;

/// \brief Provides the URI as specified in `//include/uri`. This may or may
/// not end with a file extension (it will not end with an extension if it
/// refers to a model package).
Expand Down
14 changes: 12 additions & 2 deletions include/sdf/InterfaceModel.hh
Expand Up @@ -124,10 +124,20 @@ class SDFORMAT_VISIBLE InterfaceModel
/// \brief Gets registered links.
public: const std::vector<sdf::InterfaceLink> &Links() const;

/// \brief Whether the custom parser supports merge-include.
/// \return True if the custom parser supports merge-include
public: bool ParserSupportsMergeInclude() const;

/// \brief Set whether the custom parser supports merge-include.
/// \brief[in] _val True if the custom parser supports merge-include.
public: void SetParserSupportsMergeInclude(bool _val);

/// \brief Recursively invoke the reposture callback if a the callback is set.
/// \param[in] _poseGraph Object used for resolving poses.
private: void InvokeRespostureFunction(
sdf::ScopedGraph<PoseRelativeToGraph> _graph) const;
/// \param[in] _name Override name of graph scope.
private: void InvokeRepostureFunction(
sdf::ScopedGraph<PoseRelativeToGraph> _graph,
const std::optional<std::string> &_name) const;

friend World;
friend Model;
Expand Down
11 changes: 11 additions & 0 deletions include/sdf/Model.hh
Expand Up @@ -20,6 +20,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <ignition/math/Pose3.hh>
#include <ignition/utils/ImplPtr.hh>
#include "sdf/Element.hh"
Expand All @@ -44,6 +45,8 @@ namespace sdf
struct PoseRelativeToGraph;
struct FrameAttachedToGraph;
template <typename T> class ScopedGraph;
using InterfaceModelConstPtr = std::shared_ptr<const InterfaceModel>;


class SDFORMAT_VISIBLE Model
{
Expand Down Expand Up @@ -410,12 +413,20 @@ namespace sdf
private: void SetFrameAttachedToGraph(
sdf::ScopedGraph<FrameAttachedToGraph> _graph);

/// \brief Get the list of merged interface models.
/// \return The list of merged interface models.
private: const std::vector<std::pair<std::optional<sdf::NestedInclude>,
sdf::InterfaceModelConstPtr>> &MergedInterfaceModels() const;

/// \brief Allow Root::Load, World::SetPoseRelativeToGraph, or
/// World::SetFrameAttachedToGraph to call SetPoseRelativeToGraph and
/// SetFrameAttachedToGraph
friend class Root;
friend class World;

// Allow ModelWrapper from FrameSemantics.cc to call MergedInterfaceModels
friend struct ModelWrapper;

/// \brief Private data pointer.
IGN_UTILS_IMPL_PTR(dataPtr)
};
Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Expand Up @@ -68,7 +68,7 @@ if (BUILD_TESTING)
endif()

if (TARGET UNIT_FrameSemantics_TEST)
target_sources(UNIT_FrameSemantics_TEST PRIVATE FrameSemantics.cc)
target_sources(UNIT_FrameSemantics_TEST PRIVATE FrameSemantics.cc Utils.cc)
endif()

if (TARGET UNIT_ParamPassing_TEST)
Expand Down
109 changes: 109 additions & 0 deletions src/FrameSemantics.cc
Expand Up @@ -36,6 +36,7 @@

#include "FrameSemantics.hh"
#include "ScopedGraph.hh"
#include "Utils.hh"

namespace sdf
{
Expand Down Expand Up @@ -306,6 +307,17 @@ struct LinkWrapper : public WrapperBase
{
}

/// \brief Constructor from name and pose data (without sdf::Link or
/// sdf::InterfaceLink)
LinkWrapper(const std::string &_name, const ignition::math::Pose3d &_rawPose,
const std::string &_relativeTo)
: WrapperBase{_name, "Link", FrameType::LINK},
rawPose(_rawPose),
rawRelativeTo(_relativeTo),
relativeTo(rawRelativeTo)
{
}

/// \brief Raw pose of the entity.
const ignition::math::Pose3d rawPose;
/// \brief The //pose/@relative_to attribute.
Expand Down Expand Up @@ -339,6 +351,18 @@ struct FrameWrapper : public WrapperBase
{
}

/// \brief Constructor from name, pose, and attachement data (without
/// sdf::Frame or sdf::InterfaceFrame)
FrameWrapper(const std::string &_name, const ignition::math::Pose3d &_rawPose,
const std::string &_relativeTo, const std::string &_attachedTo)
: WrapperBase{_name, "Frame", FrameType::FRAME},
rawPose(_rawPose),
rawRelativeTo(_relativeTo),
attachedTo(_attachedTo),
relativeTo(rawRelativeTo.empty() ? attachedTo : rawRelativeTo)
{
}

/// \brief Raw pose of the entity.
const ignition::math::Pose3d rawPose;
/// \brief The //pose/@relative_to attribute.
Expand Down Expand Up @@ -386,6 +410,15 @@ struct JointWrapper : public WrapperBase
const std::string relativeTo;
};

/// \brief Placement frame information
struct PlacementFrameInfo
{
/// \brief Computed name of the proxy model frame
std::string proxyName;
/// \brief The name of placement frame from //include/placement_frame.
std::string placementFrameName;
};

/// \brief Wrapper for sdf::Model and sdf::InterfaceModel
struct ModelWrapper : public WrapperBase
{
Expand Down Expand Up @@ -422,6 +455,56 @@ struct ModelWrapper : public WrapperBase
this->models.emplace_back(*_model.InterfaceModelNestedIncludeByIndex(i),
*_model.InterfaceModelByIndex(i));
}
for (const auto &[nestedInclude, model] : _model.MergedInterfaceModels())
{
const std::string proxyModelFrameName = computeMergedModelProxyFrameName(
nestedInclude->LocalModelName().value_or(model->Name()));

std::string poseRelativeTo =
nestedInclude->IncludePoseRelativeTo().value_or("");
if (poseRelativeTo.empty())
{
poseRelativeTo = "__model__";
}
this->frames.emplace_back(proxyModelFrameName,
nestedInclude->IncludeRawPose().value_or(
model->ModelFramePoseInParentFrame()),
poseRelativeTo, model->CanonicalLinkName());

for (const auto &item : model->Links())
{
this->links.emplace_back(item.Name(), item.PoseInModelFrame(),
proxyModelFrameName);
}
for (const auto &item : model->Frames())
{
std::string attachedTo = item.AttachedTo();
if (item.AttachedTo() == "__model__")
{
attachedTo = proxyModelFrameName;
}
this->frames.emplace_back(item.Name(), item.PoseInAttachedToFrame(),
attachedTo, attachedTo);
}
for (const auto &item : model->Joints())
{
std::string childName = item.ChildName();
if (item.ChildName() == "__model__")
{
childName = proxyModelFrameName;
}
this->joints.emplace_back(sdf::InterfaceJoint(item.Name(), childName,
item.PoseInChildFrame()));
}
if (nestedInclude->PlacementFrame().has_value())
{
this->mergedModelPlacements.push_back(
{proxyModelFrameName, *nestedInclude->PlacementFrame()});
}

// Skip adding nested interface models because they are already included
// in the parent model's list of nested models.
}
}

/// \brief Constructor that takes an sdf::NestedInclude and
Expand Down Expand Up @@ -479,6 +562,8 @@ struct ModelWrapper : public WrapperBase
std::vector<JointWrapper> joints;
/// \brief Children nested models and interface models.
std::vector<ModelWrapper> models;
/// \brief Placement frame information for each merged model.
std::vector<PlacementFrameInfo> mergedModelPlacements;

/// \brief Helper function to add children of interface models.
private: void AddInterfaceChildren(const sdf::InterfaceModel &_ifaceModel)
Expand Down Expand Up @@ -1014,6 +1099,30 @@ Errors wrapperBuildPoseRelativeToGraph(ScopedGraph<PoseRelativeToGraph> &_out,

outModel.UpdateEdge(rootToModel, resolvedModelPose);
}

// For each merge model, update the edge between the parent model and the
// proxy model frame to take into account the placement frame used when
// nesting the merged model via //include.
for (const auto &[proxyName, placementFrameName] :
_model.mergedModelPlacements)
{
auto proxyId = outModel.VertexIdByName(proxyName);
auto modelToProxy =
outModel.Graph().EdgeFromVertices(modelFrameId, proxyId);
const auto rawPose = modelToProxy.Data();

// We have to first set the edge data to an identity pose to be able to call
// resolveModelPoseWithPlacementFrame, which in turn calls
// sdf::resolvePoseRelativeToRoot. We will later update the edge after the
// pose is calculated.
outModel.UpdateEdge(modelToProxy, ignition::math::Pose3d::Zero);
ignition::math::Pose3d resolvedModelPose;
sdf::Errors resolveErrors =
resolveModelPoseWithPlacementFrame(rawPose,
placementFrameName, outModel, resolvedModelPose);
errors.insert(errors.end(), resolveErrors.begin(), resolveErrors.end());
outModel.UpdateEdge(modelToProxy, resolvedModelPose);
}
return errors;
}
/////////////////////////////////////////////////
Expand Down
17 changes: 16 additions & 1 deletion src/InterfaceElements.cc
Expand Up @@ -21,7 +21,10 @@ using namespace sdf;

class sdf::NestedInclude::Implementation
{

/// \brief Whether the included model should be merged as specified in
/// //include/[@merge]
/// This is nullopt if `//include/[@merge]` is is not set.
public: std::optional<bool> isMerge;
};

SDF_SUPPRESS_DEPRECATED_BEGIN
Expand Down Expand Up @@ -144,3 +147,15 @@ void NestedInclude::SetIncludeElement(sdf::ElementPtr _includeElement)
this->includeElement = _includeElement;
}
SDF_SUPPRESS_DEPRECATED_END

/////////////////////////////////////////////////
void NestedInclude::SetIsMerge(bool _isMerge)
{
this->dataPtr->isMerge = _isMerge;
}

/////////////////////////////////////////////////
const std::optional<bool> &NestedInclude::IsMerge() const
{
return this->dataPtr->isMerge;
}
28 changes: 23 additions & 5 deletions src/InterfaceModel.cc
Expand Up @@ -52,6 +52,9 @@ class InterfaceModel::Implementation

/// \brief Collection of child interface links
public: std::vector<sdf::InterfaceLink> links;

/// \brief Whether the custom parser supports merge-includes
public: bool parserSupportsMergeInclude {false};
};

InterfaceModel::InterfaceModel(const std::string &_name,
Expand Down Expand Up @@ -143,19 +146,34 @@ const std::vector<sdf::InterfaceLink> &InterfaceModel::Links() const
}

/////////////////////////////////////////////////
void InterfaceModel::InvokeRespostureFunction(
sdf::ScopedGraph<PoseRelativeToGraph> _graph) const
bool InterfaceModel::ParserSupportsMergeInclude() const
{
return this->dataPtr->parserSupportsMergeInclude;
}

/////////////////////////////////////////////////
void InterfaceModel::SetParserSupportsMergeInclude(bool _val)
{
this->dataPtr->parserSupportsMergeInclude = _val;
}

/////////////////////////////////////////////////
void InterfaceModel::InvokeRepostureFunction(
sdf::ScopedGraph<PoseRelativeToGraph> _graph,
const std::optional<std::string> &_name) const
{
const auto name = _name.value_or(this->Name());

if (this->dataPtr->repostureFunction)
{
this->dataPtr->repostureFunction(
sdf::InterfaceModelPoseGraph(this->dataPtr->name, _graph));
sdf::InterfaceModelPoseGraph(name, _graph));
}

for (const auto &nestedIfaceModel : this->dataPtr->nestedModels)
{
nestedIfaceModel->InvokeRespostureFunction(
_graph.ChildModelScope(this->Name()));
nestedIfaceModel->InvokeRepostureFunction(
_graph.ChildModelScope(name), {});
}
}
}
Expand Down