Skip to content
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