RobotImporterUtils.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <AzCore/Component/ComponentBus.h>
  10. #include <AzCore/IO/SystemFile.h>
  11. #include <AzCore/Math/Transform.h>
  12. #include <AzCore/std/containers/unordered_map.h>
  13. #include <AzCore/std/containers/unordered_set.h>
  14. #include <AzCore/std/containers/vector.h>
  15. #include <AzCore/std/function/function_template.h>
  16. #include <AzCore/std/string/string.h>
  17. #include <RobotImporter/URDF/UrdfParser.h>
  18. #include <RobotImporter/Utils/SourceAssetsStorage.h>
  19. #include <SdfAssetBuilder/SdfAssetBuilderSettings.h>
  20. #include <sdf/sdf.hh>
  21. namespace ROS2::Utils
  22. {
  23. inline namespace Internal
  24. {
  25. bool FileExistsCall(const AZ::IO::PathView& filePath);
  26. } // namespace Internal
  27. } // namespace ROS2::Utils
  28. namespace ROS2::Utils
  29. {
  30. //! Determine whether a given link is likely a wheel link.
  31. //! This can be useful to provide a good default behavior - for example, to add Vehicle Dynamics components to this link's entity.
  32. //! @param sdfModel Model object which is used to query the joints from SDF format data
  33. //! @param link the link that will be subjected to the heuristic.
  34. //! @return true if the link is likely a wheel link.
  35. bool IsWheelURDFHeuristics(const sdf::Model& model, const sdf::Link* link);
  36. //! Returns an AZ::Transform converted from the link pose defined relative to another frame.
  37. //! @param link pointer to URDF/SDF link
  38. //! @param t initial transform, multiplied against link transform
  39. //! @returns Transform of link
  40. AZ::Transform GetLocalTransformURDF(const sdf::Link* link, AZ::Transform t = AZ::Transform::Identity());
  41. //! Type Alias representing a "stack" of Model object that were visited on the way to the current Link/Joint Visitor Callback
  42. using ModelStack = AZStd::deque<AZStd::reference_wrapper<const sdf::Model>>;
  43. //! Callback which is invoke for each link within a model
  44. //! @param link reference to link being visited
  45. //! @param modelStack stack of references to the models and nested models that were visited to get to the current link. The stack will
  46. //! always contain at least one element. The back() element of the stack returns the direct model the link is attached to
  47. //! @return Return true to continue visiting links or false to halt
  48. using LinkVisitorCallback = AZStd::function<bool(const sdf::Link& link, const ModelStack& modelStack)>;
  49. //! Visit links from URDF/SDF
  50. //! @param sdfModel Model object of SDF document corresponding to the <model> tag. It used to query link
  51. //! @param visitNestedModelLinks When true recurses to any nested <model> tags of the Model object and invoke visitor on their links as
  52. //! well
  53. //! @returns void
  54. void VisitLinks(const sdf::Model& sdfModel, const LinkVisitorCallback& linkVisitorCB, bool visitNestedModelLinks = false);
  55. //! Retrieve all links in URDF/SDF as a map, where a key is link's fully qualified name and a value is a pointer to link.
  56. //! Allows to retrieve a pointer to a link given it name.
  57. //! @param sdfModel object of SDF document corresponding to the <model> tag. It used to query links
  58. //! @param gatherNestedModelLinks When true recurses to any nested <model> tags of the Model object and also gathers their links as well
  59. //! @returns mapping from fully qualified link name(such as "model_name::link_name") to link pointer
  60. AZStd::unordered_map<AZStd::string, const sdf::Link*> GetAllLinks(const sdf::Model& sdfModel, bool gatherNestedModelLinks = false);
  61. //! Callback which is invoke for each valid joint for a given model
  62. //! @param joint reference to joint being visited
  63. //! @param modelStack stack of references to the models and nested models that were visited to get to the current joint. The stack will
  64. //! always contain at least one element. The back() element of the stack returns the direct model the joint is attached to
  65. //! @return Return true to continue visiting joint or false to halt
  66. using JointVisitorCallback = AZStd::function<bool(const sdf::Joint& joint, const ModelStack& modelStack)>;
  67. //! Visit joints from URDF/SDF
  68. //! @param sdfModel Model object of SDF document corresponding to the <model> tag. It used to query joints
  69. //! @param visitNestedModelJoints When true recurses to any nested <model> tags of the Model object and invoke visitor on their joint as well
  70. //! @returns void
  71. void VisitJoints(const sdf::Model& sdfModel, const JointVisitorCallback& jointVisitorCB, bool visitNestedModelJoints = false);
  72. //! Retrieve all joints in URDF/SDF where the key is the full composed path following the name scoping proposal in SDF 1.8
  73. //! http://sdformat.org/tutorials?tut=composition_proposal#1-nesting-and-encapsulation
  74. //! @param sdfModel Model object of SDF document corresponding to the <model> tag. It used to query joints
  75. //! @param gatherNestedModelJoints When true recurses to any nested <model> tags of the Model object and also gathers their joints as well
  76. //! @returns mapping from fully qualified joint name(such as "model_name::joint_name") to joint pointer
  77. AZStd::unordered_map<AZStd::string, const sdf::Joint*> GetAllJoints(const sdf::Model& sdfModel, bool gatherNestedModelJoints = false);
  78. //! Retrieve all joints from URDF/SDF in which the specified link is a child in a sdf::Joint.
  79. //! @param sdfModel Model object of SDF document corresponding to the <model> tag. It used to query joints
  80. //! @param linkName Name of link which to query in joint objects ChildName()
  81. //! @param gatherNestedModelJoints When true recurses to any nested <model> tags of the Model object and also gathers their joints as well
  82. //! @returns vector of joints where link is a child
  83. AZStd::vector<const sdf::Joint*> GetJointsForChildLink(
  84. const sdf::Model& sdfModel, AZStd::string_view linkName, bool gatherNestedModelJoints = false);
  85. //! Retrieve all joints from URDF/SDF in which the specified link is a parent in a sdf::Joint.
  86. //! @param sdfModel Model object of SDF document corresponding to the <model> tag. It used to query joints
  87. //! @param linkName Name of link which to query in joint objects ParentName()
  88. //! @param gatherNestedModelJoints When true recurses to any nested <model> tags of the Model object and also gathers their joints as well
  89. //! @returns vector of joints where link is a parent
  90. AZStd::vector<const sdf::Joint*> GetJointsForParentLink(
  91. const sdf::Model& sdfModel, AZStd::string_view linkName, bool gatherNestedModelJoints = false);
  92. //! Visitation Enum to determine if visiting models should halt, continue to visit sibling models or continue to visit
  93. //! sibling and nested models of the current model
  94. enum class VisitModelResponse
  95. {
  96. //! Visit any nested model of the current model, and then continue to visit sibling models
  97. VisitNestedAndSiblings,
  98. //! If returned, sibling <model> to the current model will be visited,
  99. //! but not any nested children
  100. VisitSiblings,
  101. //! Stop visitation of future sibling <model> tags or nested <model> to the current model
  102. Stop,
  103. };
  104. //! Callback which is invoke for each model in the SDF
  105. //! This function visits any <model> tags in the root of the SDF XML content
  106. //! as well as any <model> tags in any <world> tags that are in the root of the SDF XML content
  107. //! @param model reference to SDF model object being visited
  108. //! @param modelStack stack of references to the models were visited to get to the current model
  109. //! NOTE: Unlike the Link/Joint visitor the modelStack can be empty (i.e for the root model or a model that is a child of a <world>)
  110. //! @return Return true to continue visiting models or false to halt
  111. using ModelVisitorCallback = AZStd::function<VisitModelResponse(const sdf::Model& model, const ModelStack& modelStack)>;
  112. //! Visit Models from URDF/SDF
  113. //! @param sdfRoot Root object of SDF document
  114. //! @param visitNestedModels When true recurses to any nested <model> tags of the Model objects and invoke the visitor on them
  115. //! @returns void
  116. void VisitModels(const sdf::Root& sdfRoot, const ModelVisitorCallback& modelVisitorCB, bool visitNestedModels = true);
  117. //! @param sdfWorld World object of SDF document corresponding to the <world> tag.
  118. //! @param visitNestedModels When true recurses to any nested <model> tags of the Model objects and invoke the visitor on them
  119. //! @returns void
  120. void VisitModels(const sdf::World& sdfWorld, const ModelVisitorCallback& modelVisitorCB, bool visitNestedModels = true);
  121. //! @param sdfModel Model object corresponding to a <model> tag in the SDF.
  122. //! @param visitNestedModels When true recurses to any nested <model> tags of the Model objects and invoke the visitor on them
  123. //! @returns void
  124. void VisitModels(const sdf::Model& sdfModel, const ModelVisitorCallback& modelVisitorCB, bool visitNestedModels = true);
  125. using ModelMap = AZStd::unordered_map<AZStd::string, const sdf::Model*>;
  126. //! Retrieve all models in URDF/SDF where the key is the fully composed path following the name scoping proposal in SDF 1.8
  127. //! http://sdformat.org/tutorials?tut=composition_proposal#1-nesting-and-encapsulation
  128. //! @param sdfRoot Root object of SDF document. The SDF <world> and <model> tags are recursed to locate SDF models
  129. //! @param gatherNestedModelsForModel When true recurses to any nested <model> tags of the Model object and also gathers their models as well
  130. //! @returns mapping from fully qualified model name(such as "model_name::nested_model_name") to model pointer
  131. //! NOTE: For the SDF world object if gatherNestedModelsForModel=false, then only the direct models of the world are gathered
  132. ModelMap GetAllModels(const sdf::Root& sdfRoot, bool gatherNestedModelsForModel = false);
  133. //! @param sdfWorld World object of SDF document corresponding to the <world> tag. It used to query models
  134. //! @param gatherNestedModelsForModel When true recurses to any nested <model> tags of the Model object and also gathers their models as well
  135. //! @returns mapping from fully qualified model name(such as "model_name::nested_model_name") to model pointer
  136. ModelMap GetAllModels(const sdf::World& sdfWorld, bool gatherNestedModelsForModel = false);
  137. //! @param sdfModel Model object corresponding to a <model> tag in the SDF. It used to query nested models
  138. //! @param gatherNestedModelsForModel When true recurses to any nested <model> tags of the Model object and also gathers their models as well
  139. //! @returns mapping from fully qualified model name(such as "model_name::nested_model_name") to model pointer
  140. ModelMap GetAllModels(const sdf::Model& sdfModel, bool gatherNestedModelsForModel = false);
  141. //! Returns the SDF model object which contains the specified link
  142. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  143. //! @param linkName Fully qualified name of SDF link to lookup in the SDF document
  144. //! A fully qualified name has the form "modelname1::nested_modelname1::linkname"
  145. //! This is detailed in the SDF format composition proposal: http://sdformat.org/tutorials?tut=composition_proposal#motivation
  146. const sdf::Model* GetModelContainingLink(const sdf::Root& root, AZStd::string_view linkName);
  147. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  148. //! @param link SDF link reference to lookup in the SDF document
  149. const sdf::Model* GetModelContainingLink(const sdf::Root& root, const sdf::Link& link);
  150. //! Returns the SDF model object which contains the specified joint
  151. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  152. //! @param jointName Name of SDF joint to lookup in the SDF document
  153. //! A fully qualified name has the form "modelname1::nested_modelname1::jointname"
  154. //! This is detailed in the SDF format composition proposal: http://sdformat.org/tutorials?tut=composition_proposal#motivation
  155. const sdf::Model* GetModelContainingJoint(const sdf::Root& root, AZStd::string_view jointName);
  156. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  157. //! @param joint SDF joint reference to lookup in the SDF document
  158. const sdf::Model* GetModelContainingJoint(const sdf::Root& root, const sdf::Joint& joint);
  159. //! Returns the SDF model object which contains the specified model
  160. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  161. //! @param model SDF model reference to lookup in the SDF document
  162. //! @return pointer to parent model containing this model if the model is nested, otherwise nullptr
  163. const sdf::Model* GetModelContainingModel(const sdf::Root& root, const sdf::Model& model);
  164. //! Retrieve all assets referenced in SDF/URDF as unresolved URIs.
  165. //! The URIs will still need to get resolved via ResolveAssetPath() to point to a valid file location.
  166. //! @param root reference to SDF Root object representing the root of the parsed SDF xml document
  167. //! @returns set of meshes' filenames.
  168. AssetFilenameReferences GetReferencedAssetFilenames(const sdf::Root& root);
  169. //! Callback used to check for file exist of a path referenced within a URDF/SDF file
  170. //! @param path Candidate local filesystem path to check for existence
  171. //! @return true should be returned if the file exist otherwise false
  172. using FileExistsCB = AZStd::function<bool(const AZ::IO::PathView&)>;
  173. //! Resolves path for an asset referenced in a URDF/SDF file.
  174. //! @param unresolvedPath unresolved URDF/SDF path, example : `model://meshes/foo.dae`.
  175. //! @param baseFilePath the absolute path of URDF/SDF file which contains the path that is to be resolved.
  176. //! @param amentPrefixPath the string that contains available packages' path, separated by ':' signs.
  177. //! @param settings the asset path resolution settings to use for attempting to locate the correct files
  178. //! @param fileExists functor to check if the given file exists. Exposed for unit test, default one should be used.
  179. //! @returns resolved path to the referenced file within the URDF/SDF, or the passed-in path if no resolution was possible.
  180. AZ::IO::Path ResolveAssetPath(
  181. AZ::IO::Path unresolvedPath,
  182. const AZ::IO::PathView& baseFilePath,
  183. AZStd::string_view amentPrefixPath,
  184. const SdfAssetBuilderSettings& settings,
  185. const FileExistsCB& fileExists = &Internal::FileExistsCall);
  186. using AmentPrefixString = AZStd::fixed_string<32768>;
  187. AmentPrefixString GetAmentPrefixPath();
  188. } // namespace ROS2::Utils
  189. namespace ROS2::Utils::SDFormat
  190. {
  191. //! Retrieve plugin's filename. The filepath is converted into the filename if necessary.
  192. //! @param plugin plugin in the parsed SDFormat data
  193. //! @returns filename (including extension) without path
  194. AZStd::string GetPluginFilename(const sdf::Plugin& plugin);
  195. //! Retrieve all parameters that were defined for an element in XML data that are not supported in O3DE.
  196. //! Allows to store the list of unsupported parameters in metadata and logs. It is typically used with sensors and plugins.
  197. //! @param rootElement pointer to a root Element in parsed XML data that will be a subject to heuristics
  198. //! @param supportedParams set of predefined parameters that are supported
  199. //! @returns list of unsupported parameters defined for given element
  200. AZStd::vector<AZStd::string> GetUnsupportedParams(
  201. const sdf::ElementPtr& rootElement, const AZStd::unordered_set<AZStd::string>& supportedParams);
  202. //! Check if plugin is supported by using it's filename. The filepath is converted into the filename if necessary.
  203. //! @param plugin plugin in the parsed SDFormat data
  204. //! @param supportedPlugins set of predefined plugins that are supported
  205. //! @returns true if plugin is supported
  206. bool IsPluginSupported(const sdf::Plugin& plugin, const AZStd::unordered_set<AZStd::string>& supportedPlugins);
  207. //! Given a set of SdfAssetBuilderSettings, produce an sdf::ParserConfig that can be used by the sdformat library.
  208. //! @param settings The input settings to use
  209. //! @param baseFilePath The base file getting parsed, which is used to help resolve file paths
  210. //! @return The output parser config to use with sdformat.
  211. sdf::ParserConfig CreateSdfParserConfigFromSettings(const SdfAssetBuilderSettings& settings, const AZ::IO::PathView& baseFilePath);
  212. } // namespace ROS2::Utils::SDFormat