Skip to content
Open
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
13 changes: 13 additions & 0 deletions include/sdf/InterfaceElements.hh
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ class SDFORMAT_VISIBLE NestedInclude
/// \param[in] _localModelName The local name
public: void SetLocalModelName(const std::string &_localModelName);

/// \brief Namespace relative to immediate parent as specified in
/// `//include/namespace`. This is nullopt if `//include/namespace` is not
/// set. Then the namespace of the model must be determined by the custom
/// model parser from the included model file.
/// Example: `my_new_model_namespace`
/// \return The local namespace. nullopt if `//include/namespace` is not set
public: const std::optional<std::string> &LocalModelNamespace() const;

/// \brief Set the namespace relative to immediate parent as specified in
/// `//include/namespace`
/// \param[in] _localModelNs The local namespace
public: void SetLocalModelNamespace(const std::string &_localModelNs);

/// \brief Whether the model is static as defined by `//include/static`. This
/// is nullopt if `//include/static` is not set.
/// \return Whether the model is static. nullopt if `//include/static` is not
Expand Down
23 changes: 23 additions & 0 deletions include/sdf/Model.hh
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ namespace sdf
/// \param[in] _name Name of the model.
public: void SetName(const std::string &_name);

/// \brief Get the resolved namespace associated with the model.
/// \return Resolved namespace of the model if it has been set,
/// otherwise std::nullopt.
public: std::optional<std::string> Namespace() const;

/// \brief Get the raw namespace associated with the model.
/// \return Raw namespace of the model if it has been set,
/// otherwise std::nullopt.
public: std::optional<std::string> RawNamespace() const;

/// \brief Set the raw namespace associated with the model.
/// \param[in] _ns Raw namespace of the model. The `__name__` placeholder
/// will be replaced with the model name.
public: void SetRawNamespace(const std::string &_ns);

/// \brief Check if this model should be static.
/// A static model is one that is not subject to physical forces (in other
/// words, it's purely kinematic instead of dynamic).
Expand Down Expand Up @@ -557,6 +572,14 @@ namespace sdf
private: sdf::Frame PrepareForMerge(sdf::Errors &_errors,
const std::string &_parentOfProxyFrame);

/// \brief Resolve namespace placeholders for this model.
/// \param[in] _rawNs The raw namespace string.
/// \param[in] _modelName The model name used to replace "__name__".
/// \return The namespace string with model placeholders resolved.
private: std::optional<std::string> ResolveNamespace (
const std::optional<std::string> &_rawNs,
const std::string &_modelName);

/// \brief Allow Root::Load, World::SetPoseRelativeToGraph, or
/// World::SetFrameAttachedToGraph to call SetPoseRelativeToGraph and
/// SetFrameAttachedToGraph
Expand Down
13 changes: 13 additions & 0 deletions sdf/1.11/model.sdf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
</description>
</attribute>

<attribute name="namespace" type="string" default="" required="0">
<description>
Optional namespace associated with the model. This namespace can be
used by downstream systems and applications to organize related entities
and communication interfaces. The `__name__` placeholder will be
replaced with the model name.
</description>
</attribute>

<attribute name="canonical_link" type="string" default="" required="0">
<description>
The name of the model's canonical link, to which the model's implicit
Expand Down Expand Up @@ -69,6 +78,10 @@
<description>Override the name of the included model.</description>
</element>

<element name="namespace" type="string" default="" required="0">
<description>Override the namespace of the included model.</description>
</element>

<element name="static" type="bool" default="false" required="0">
<description>Override the static value of the included model.</description>
</element>
Expand Down
4 changes: 4 additions & 0 deletions sdf/1.11/world.sdf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
<description>Override the static value of the included entity.</description>
</element>

<element name="namespace" type="string" default="" required="0">
<description>Override the namespace of the included model.</description>
</element>

<include filename="pose.sdf" required="0"/>
<include filename="plugin.sdf" required="*"/>

Expand Down
13 changes: 13 additions & 0 deletions sdf/1.12/model.sdf
Comment thread
C88-YQ marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
</description>
</attribute>

<attribute name="namespace" type="string" default="" required="0">
<description>
Optional namespace associated with the model. This namespace can be
used by downstream systems and applications to organize related entities
and communication interfaces. The `__name__` placeholder will be
replaced with the model name.
</description>
</attribute>

<attribute name="canonical_link" type="string" default="" required="0">
<description>
The name of the model's canonical link, to which the model's implicit
Expand Down Expand Up @@ -70,6 +79,10 @@
<description>Override the name of the included model.</description>
</element>

<element name="namespace" type="string" default="" required="0">
<description>Override the namespace of the included model.</description>
</element>

<element name="static" type="bool" default="false" required="0">
<description>Override the static value of the included model.</description>
</element>
Expand Down
4 changes: 4 additions & 0 deletions sdf/1.12/world.sdf
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<description>Override the name of the included entity.</description>
</element>

<element name="namespace" type="string" default="" required="0">
<description>Override the namespace of the included model.</description>
</element>

<element name="static" type="bool" default="false" required="0">
<description>Override the static value of the included entity.</description>
</element>
Expand Down
19 changes: 19 additions & 0 deletions src/InterfaceElements.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ class sdf::NestedInclude::Implementation
/// Example: `my_new_model`
public: std::optional<std::string> localModelName;

/// \brief Namespace relative to immediate parent as specified in
/// `//include/namespace`. This is nullopt if `//include/namespace` is not
/// set. Then the namespace of the model must be determined by the custom
/// model parser from the included model file.
/// Example: `my_new_model_namespace`
public: std::optional<std::string> localModelNs;

/// \brief Whether the model is static as defined by `//include/static`. This
/// is nullopt if `//include/static` is not set.
public: std::optional<bool> isStatic;
Expand Down Expand Up @@ -129,6 +136,18 @@ void NestedInclude::SetLocalModelName(const std::string &_localModelName)
this->dataPtr->localModelName = _localModelName;
}

/////////////////////////////////////////////////
const std::optional<std::string> &NestedInclude::LocalModelNamespace() const
{
return this->dataPtr->localModelNs;
}

/////////////////////////////////////////////////
void NestedInclude::SetLocalModelNamespace(const std::string &_localModelNs)
{
this->dataPtr->localModelNs = _localModelNs;
}

/////////////////////////////////////////////////
const std::optional<bool> &NestedInclude::IsStatic() const
{
Expand Down
68 changes: 68 additions & 0 deletions src/Model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
*/
#include <memory>
#include <optional>
#include <string>
#include <unordered_set>
#include <vector>
Expand Down Expand Up @@ -44,6 +45,12 @@ class sdf::Model::Implementation
/// \brief Name of the model.
public: std::string name = "";

/// \brief The unresolved namespace specified by the user.
public: std::optional<std::string> rawNamespace;

/// \brief The namespace after model name placeholders have been resolved.
public: std::optional<std::string> resolvedNamespace;

/// \brief True if this model is specified as static, false otherwise.
public: bool isStatic = false;

Expand Down Expand Up @@ -178,6 +185,15 @@ Errors Model::Load(sdf::ElementPtr _sdf, const ParserConfig &_config)
"] is reserved."});
}

// Read the model's namespace
auto nsAttribute = _sdf->GetAttribute("namespace");
if (nsAttribute && nsAttribute->GetSet())
{
this->dataPtr->rawNamespace = _sdf->Get<std::string>("namespace", "").first;
this->dataPtr->resolvedNamespace =
this->ResolveNamespace(this->dataPtr->rawNamespace, this->Name());
}

// Read the model's canonical_link attribute
if (_sdf->HasAttribute("canonical_link"))
{
Expand Down Expand Up @@ -534,6 +550,28 @@ std::string Model::Name() const
void Model::SetName(const std::string &_name)
{
this->dataPtr->name = _name;
this->dataPtr->resolvedNamespace =
this->ResolveNamespace(this->dataPtr->rawNamespace, _name);
}

/////////////////////////////////////////////////
std::optional<std::string> Model::Namespace() const
{
return this->dataPtr->resolvedNamespace;
}

/////////////////////////////////////////////////
std::optional<std::string> Model::RawNamespace() const
{
return this->dataPtr->rawNamespace;
}

/////////////////////////////////////////////////
void Model::SetRawNamespace(const std::string &_ns)
{
this->dataPtr->rawNamespace = _ns;
this->dataPtr->resolvedNamespace =
this->ResolveNamespace(this->dataPtr->rawNamespace, this->Name());
}

/////////////////////////////////////////////////
Expand Down Expand Up @@ -1094,6 +1132,11 @@ sdf::ElementPtr Model::ToElement(const OutputConfig &_config) const
sdf::ElementPtr includeElem = worldElem->AddElement("include");
includeElem->GetElement("uri")->Set(this->Uri());
includeElem->GetElement("name")->Set(this->Name());
const auto rawNamespace = this->RawNamespace();
if (rawNamespace.has_value())
{
includeElem->GetElement("namespace")->Set(rawNamespace.value());
}
includeElem->GetElement("pose")->Set(this->RawPose());
if (!this->dataPtr->poseRelativeTo.empty())
{
Expand All @@ -1117,6 +1160,11 @@ sdf::ElementPtr Model::ToElement(const OutputConfig &_config) const
sdf::ElementPtr elem(new sdf::Element);
sdf::initFile("model.sdf", elem);
elem->GetAttribute("name")->Set(this->Name());
const auto rawNamespace = this->RawNamespace();
if (rawNamespace.has_value())
{
elem->GetAttribute("namespace")->Set(rawNamespace.value());
}

if (!this->dataPtr->canonicalLink.empty())
{
Expand Down Expand Up @@ -1414,3 +1462,23 @@ sdf::Frame Model::PrepareForMerge(sdf::Errors &_errors,

return proxyFrame;
}

std::optional<std::string> Model::ResolveNamespace(
const std::optional<std::string> &_rawNs,
const std::string &_modelName)
{
if (_rawNs == std::nullopt)
{
return std::nullopt;
}

std::optional<std::string> resolved = _rawNs;
std::size_t pos = 0;

while ((pos = resolved->find("__name__", pos)) != std::string::npos)
{
resolved->replace(pos, strlen("__name__"), _modelName);
pos += _modelName.size();
}
return resolved;
}
Loading