CommonUtilities.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. #include "CommonUtilities.h"
  9. #include "Components/NamedPoseComponent.h"
  10. #include "SimulationInterfaces/NamedPoseManagerRequestBus.h"
  11. #include <AzCore/Component/EntityId.h>
  12. #include <AzCore/std/containers/vector.h>
  13. #include <AzCore/std/ranges/ranges_algorithm.h>
  14. #include <AzCore/std/string/string.h>
  15. #include <AzFramework/Components/TransformComponent.h>
  16. #include <AzFramework/Physics/Components/SimulatedBodyComponentBus.h>
  17. #include <AzFramework/Physics/Shape.h>
  18. #include <simulation_interfaces/msg/tags_filter.hpp>
  19. namespace SimulationInterfaces::Utils
  20. {
  21. const char* const ProductAssetPrefix = "product_asset:///";
  22. AZStd::string RelPathToUri(AZStd::string_view relPath)
  23. {
  24. AZStd::string uri = relPath;
  25. AZStd::replace(uri.begin(), uri.end(), '\\', '/');
  26. uri.insert(0, ProductAssetPrefix);
  27. return uri;
  28. }
  29. AZStd::string UriToRelPath(AZStd::string_view uri)
  30. {
  31. if (uri.starts_with(ProductAssetPrefix))
  32. {
  33. const AZStd::string_view productAssetPrefix{ ProductAssetPrefix };
  34. return uri.substr(productAssetPrefix.length());
  35. }
  36. return {};
  37. }
  38. bool AreTagsMatching(const TagFilter& tagFilter, const AZStd::vector<AZStd::string>& entityTags)
  39. {
  40. if (tagFilter.m_tags.empty())
  41. {
  42. return true;
  43. }
  44. bool matchAllTags = tagFilter.m_mode == simulation_interfaces::msg::TagsFilter::FILTER_MODE_ALL;
  45. for (auto& tag : tagFilter.m_tags)
  46. {
  47. bool tagExistInEntity = AZStd::ranges::contains(entityTags, tag);
  48. // if all tags need to match but entity doesn't have requested one, return with false
  49. if (matchAllTags && !tagExistInEntity)
  50. {
  51. return false;
  52. }
  53. // if match any and first match found, condition already satisfied, return with true
  54. if (!matchAllTags && tagExistInEntity)
  55. {
  56. return true;
  57. }
  58. }
  59. // if code goes here it means it went through whole loop, In MATCH_ALL mode it means all tags were found => return true
  60. // In MATCH_ANY it means no match was found, return false
  61. // this logical AND handles these cases
  62. return matchAllTags && true;
  63. }
  64. AZStd::unordered_map<AZStd::string, AZ::EntityId> FilterNamedPosesByTag(
  65. const AZStd::unordered_map<AZStd::string, AZ::EntityId>& entitiesToFilter, const TagFilter& tagFilter)
  66. {
  67. AZStd::unordered_map<AZStd::string, AZ::EntityId> filteredEntities;
  68. for (auto& [name, entityId] : entitiesToFilter)
  69. {
  70. NamedPose configuration;
  71. NamedPoseComponentRequestBus::EventResult(configuration, entityId, &NamedPoseComponentRequests::GetConfiguration);
  72. if (AreTagsMatching(tagFilter, configuration.m_tags))
  73. {
  74. filteredEntities[name] = entityId;
  75. }
  76. }
  77. return filteredEntities;
  78. }
  79. AZ::Outcome<AzPhysics::SimulatedBody*, AZStd::string> GetSimulatedBody(AZ::EntityId entityId)
  80. {
  81. AzPhysics::SimulatedBody* simulatedBody = nullptr;
  82. AzPhysics::SimulatedBodyComponentRequestsBus::EventResult(
  83. simulatedBody, entityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody);
  84. if (simulatedBody == nullptr)
  85. {
  86. const auto msg = AZStd::string::format("Entity's simulated body doesn't exist");
  87. return AZ::Failure(msg);
  88. }
  89. if (simulatedBody->m_bodyHandle == AzPhysics::InvalidSimulatedBodyHandle)
  90. {
  91. const auto msg = AZStd::string::format("Entity is not a valid simulated body");
  92. return AZ::Failure(msg);
  93. }
  94. return AZ::Success(simulatedBody);
  95. }
  96. AZ::Outcome<Bounds, AZStd::string> ConvertPhysicalShapeToBounds(AZStd::shared_ptr<Physics::Shape> shape, const AZ::EntityId& entityId)
  97. {
  98. auto config = shape->GetShapeConfiguration();
  99. auto shapeType = config->GetShapeType();
  100. // get final collider transform including entity TM and offsets
  101. auto [colliderOffsetTranslation, collideerOffsetRotation] = shape->GetLocalPose();
  102. AZ::Transform offsetTransform =
  103. AZ::Transform::CreateFromQuaternionAndTranslation(collideerOffsetRotation, colliderOffsetTranslation);
  104. AZ::Transform entityTransform;
  105. AZ::TransformBus::EventResult(entityTransform, entityId, &AZ::TransformBus::Events::GetWorldTM);
  106. AZ::Transform colliderAbsoluteTransform = entityTransform * offsetTransform;
  107. Bounds bounds;
  108. switch (shapeType)
  109. {
  110. case Physics::ShapeType::Box:
  111. {
  112. bounds.m_boundsType = simulation_interfaces::msg::Bounds::TYPE_BOX;
  113. auto boxConfig = azdynamic_cast<Physics::BoxShapeConfiguration*>(config);
  114. bounds.m_points.emplace_back(colliderAbsoluteTransform.GetTranslation() + (boxConfig->m_dimensions / 2)); // upper Right
  115. bounds.m_points.emplace_back(colliderAbsoluteTransform.GetTranslation() - (boxConfig->m_dimensions / 2)); // bottom left
  116. return bounds;
  117. }
  118. case Physics::ShapeType::Sphere:
  119. {
  120. bounds.m_boundsType = simulation_interfaces::msg::Bounds::TYPE_SPHERE;
  121. auto sphereConfig = azdynamic_cast<Physics::SphereShapeConfiguration*>(config);
  122. bounds.m_points.emplace_back(colliderAbsoluteTransform.GetTranslation()); // sphere center
  123. bounds.m_points.emplace_back(sphereConfig->m_radius, 0.f, 0.f); // radius and two ignored fields
  124. return bounds;
  125. }
  126. // this type of collider is currently unsupported by the PhysX engine, but this implementation uses provided abstractions and is
  127. // independent from selected physics engine.
  128. case Physics::ShapeType::ConvexHull:
  129. {
  130. bounds.m_boundsType = simulation_interfaces::msg::Bounds::TYPE_CONVEX_HULL;
  131. AZStd::vector<AZ::Vector3> vertices;
  132. AZStd::vector<AZ::u32> indices;
  133. shape->GetGeometry(vertices, indices);
  134. for (auto& vertex : vertices)
  135. {
  136. bounds.m_points.emplace_back(colliderAbsoluteTransform.TransformPoint(vertex));
  137. }
  138. return bounds;
  139. }
  140. default:
  141. {
  142. return AZ::Failure(AZStd::string::format(
  143. "Passed shape type with id %d is not supported by simulation interfaces", static_cast<AZ::u8>(shapeType)));
  144. }
  145. }
  146. }
  147. simulation_interfaces::msg::WorldResource ConvertToRos2WorldResource(const SimulationInterfaces::WorldResource& resource)
  148. {
  149. simulation_interfaces::msg::WorldResource worldResource;
  150. worldResource.name = resource.m_name.c_str();
  151. worldResource.description = resource.m_description.c_str();
  152. worldResource.world_resource.uri = resource.m_worldResource.m_uri.c_str();
  153. worldResource.world_resource.resource_string = resource.m_worldResource.m_resourceString.c_str();
  154. AZStd::ranges::transform(resource.m_tags, AZStd::back_inserter(worldResource.tags), &AZStd::string::c_str);
  155. return worldResource;
  156. }
  157. } // namespace SimulationInterfaces::Utils