CommonUtilities.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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/EntityId.h>
  10. #include <AzCore/Outcome/Outcome.h>
  11. #include <AzCore/std/containers/unordered_map.h>
  12. #include <AzCore/std/ranges/ranges_algorithm.h>
  13. #include <AzCore/std/smart_ptr/make_shared.h>
  14. #include <AzCore/std/string/string.h>
  15. #include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
  16. #include <LmbrCentral/Scripting/TagComponentBus.h>
  17. #include <ROS2/Utilities/ROS2Conversions.h>
  18. #include <SimulationInterfaces/Bounds.h>
  19. #include <SimulationInterfaces/SimulationEntityManagerRequestBus.h>
  20. #include <SimulationInterfaces/TagFilter.h>
  21. #include <SimulationInterfaces/WorldResource.h>
  22. #include <simulation_interfaces/msg/entity_category.hpp>
  23. #include <simulation_interfaces/msg/world_resource.hpp>
  24. namespace SimulationInterfaces::Utils
  25. {
  26. //! Convert a relative path to a URI
  27. //! relative path: "path/to/file.txt"
  28. //! URI: "product_asset:///path/to/file.txt"
  29. AZStd::string RelPathToUri(AZStd::string_view relPath);
  30. AZStd::string UriToRelPath(AZStd::string_view relPath);
  31. //! Filter named poses given by map by given tag filter
  32. //! @param entitiesToFilter map [entityName,entityId] describing NamedPoses which should be processed
  33. //! @param tagFilter definition of tag filter to apply
  34. AZStd::unordered_map<AZStd::string, AZ::EntityId> FilterNamedPosesByTag(
  35. const AZStd::unordered_map<AZStd::string, AZ::EntityId>& entitiesToFilter, const TagFilter& tagFilter);
  36. //! Helper function to check if entity tags matcher with given filter
  37. //! @param tagFilter filter defined by simulation interfaces with rules of the tag matching
  38. //! @param entityTags tags assigned to entity which is being tested
  39. //! @return status of tag matching
  40. bool AreTagsMatching(const TagFilter& tagFilter, const AZStd::vector<AZStd::string>& entityTags);
  41. //! Helper function to retrieve simulated body from the entity byt given ID
  42. //! @param entityId entity ID of the entity with potential simulated body
  43. //! @return pointer to simulated body, or failure in case when simulated body wasn't found
  44. AZ::Outcome<AzPhysics::SimulatedBody*, AZStd::string> GetSimulatedBody(AZ::EntityId entityId);
  45. //! Helper function which converts collider to Bounds defined by the simulation interfaces
  46. //! @param shape physics shape you want to convert
  47. //! @param entityId id of the physical shape owner
  48. //! @return simulation interfaces style bound or failure in something was wrong during processing
  49. AZ::Outcome<Bounds, AZStd::string> ConvertPhysicalShapeToBounds(AZStd::shared_ptr<Physics::Shape> shape, const AZ::EntityId& entityId);
  50. //! Helper function which converts ROS 2 request with entity Filter to structure defined by SimulationInterfaces Gem
  51. //! @param request ROS 2 request with field `filters`
  52. //! @return EntityFilter structure or error message if something went wrong
  53. template<typename RequestType>
  54. AZ::Outcome<SimulationInterfaces::EntityFilters, AZStd::string> GetEntityFiltersFromRequest(const RequestType& request)
  55. {
  56. SimulationInterfaces::EntityFilters filter;
  57. filter.m_nameFilter = request.filters.filter.c_str();
  58. uint8_t type = request.filters.bounds.type;
  59. if (type == simulation_interfaces::msg::Bounds::TYPE_BOX)
  60. {
  61. if (request.filters.bounds.points.size() != 2)
  62. {
  63. return AZ::Failure("Invalid number of points! Type 'TYPE_BOX' should have exactly 2 points.");
  64. }
  65. const auto& p1 = request.filters.bounds.points.front();
  66. const auto& p2 = request.filters.bounds.points.back();
  67. // https://github.com/ros-simulation/simulation_interfaces/blob/main/msg/Bounds.msg
  68. // Axis-aligned bounding box, points field should have two values, which are upper right and lower left corners of the box.
  69. if (p1.x < p2.x || p1.y < p2.y || p1.z < p2.z)
  70. {
  71. return AZ::Failure("Invalid points! The first point should be higher than the second point.");
  72. }
  73. const auto max = ROS2::ROS2Conversions::FromROS2Vector3(p1);
  74. const auto min = ROS2::ROS2Conversions::FromROS2Vector3(p2);
  75. const AZ::Aabb aabb = AZ::Aabb::CreateFromMinMax(min, max);
  76. filter.m_boundsShape = AZStd::make_shared<Physics::BoxShapeConfiguration>(aabb.GetExtents());
  77. }
  78. else if (type == simulation_interfaces::msg::Bounds::TYPE_CONVEX_HULL)
  79. {
  80. if (request.filters.bounds.points.size() < 3)
  81. {
  82. return AZ::Failure("Invalid number of points! Type 'TYPE_CONVEX_HULL' should have at least 3 points.");
  83. }
  84. // TODO: Implement convex hull shape configuration
  85. // filter.m_boundsShape = AZStd::make_shared<Physics::ConvexHullShapeConfiguration>();
  86. return AZ::Failure("Unsupported type! Type 'TYPE_CONVEX_HULL' is not supported.");
  87. }
  88. else if (type == simulation_interfaces::msg::Bounds::TYPE_SPHERE)
  89. {
  90. if (request.filters.bounds.points.size() != 2)
  91. {
  92. return AZ::Failure("Invalid number of points! Type 'TYPE_SPHERE' should have exactly 2 points.");
  93. }
  94. filter.m_boundsShape = AZStd::make_shared<Physics::SphereShapeConfiguration>(request.filters.bounds.points.back().x);
  95. filter.m_boundsPose = { ROS2::ROS2Conversions::FromROS2Vector3(request.filters.bounds.points.front()),
  96. AZ::Quaternion::CreateIdentity(),
  97. 1.0f };
  98. }
  99. // copy categories
  100. AZStd::ranges::transform(
  101. request.filters.categories,
  102. AZStd::back_inserter(filter.m_entityCategories),
  103. &simulation_interfaces::msg::EntityCategory::category);
  104. filter.m_tagsFilter.m_mode = request.filters.tags.filter_mode;
  105. // copy tags
  106. AZStd::ranges::transform(
  107. request.filters.tags.tags, AZStd::inserter(filter.m_tagsFilter.m_tags, filter.m_tagsFilter.m_tags.end()), &std::string::c_str);
  108. return AZ::Success(AZStd::move(filter));
  109. }
  110. //! Helper function to convert WorldResource defined by SimulationInterfaces Gem to structure defined by ROS 2
  111. //! @param resource data to convert
  112. //! @return ROS 2 version of WorldResource
  113. simulation_interfaces::msg::WorldResource ConvertToRos2WorldResource(const SimulationInterfaces::WorldResource& resource);
  114. } // namespace SimulationInterfaces::Utils