Переглянути джерело

Merge pull request #916 from RobotecAI/jh/release_25050

Merge `stabilization/25050` into `main`
Jan Hanca 1 місяць тому
батько
коміт
06fe5bdcb8
100 змінених файлів з 2108 додано та 602 видалено
  1. 1 3
      .gitattributes
  2. 61 0
      Gems/LevelGeoreferencing/.clang-format
  3. 10 0
      Gems/LevelGeoreferencing/CMakeLists.txt
  4. 257 0
      Gems/LevelGeoreferencing/Code/CMakeLists.txt
  5. 36 4
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceBus.h
  6. 97 0
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceStructures.h
  7. 31 0
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferencingTypeIds.h
  8. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Android/PAL_android.cmake
  9. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_api_files.cmake
  10. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_private_files.cmake
  11. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_shared_files.cmake
  12. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/PAL_linux.cmake
  13. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_api_files.cmake
  14. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_editor_api_files.cmake
  15. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_private_files.cmake
  16. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_shared_files.cmake
  17. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/PAL_mac.cmake
  18. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_api_files.cmake
  19. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_editor_api_files.cmake
  20. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_private_files.cmake
  21. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_shared_files.cmake
  22. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/PAL_windows.cmake
  23. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_api_files.cmake
  24. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_editor_api_files.cmake
  25. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_private_files.cmake
  26. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_shared_files.cmake
  27. 8 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/PAL_ios.cmake
  28. 7 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_api_files.cmake
  29. 12 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_private_files.cmake
  30. 12 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_shared_files.cmake
  31. 3 3
      Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.cpp
  32. 4 3
      Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.h
  33. 50 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.cpp
  34. 29 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.h
  35. 68 9
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.cpp
  36. 20 5
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.h
  37. 19 67
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceStructures.cpp
  38. 26 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingModule.cpp
  39. 58 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.cpp
  40. 38 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.h
  41. 42 0
      Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.cpp
  42. 30 0
      Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.h
  43. 4 3
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.cpp
  44. 12 14
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.h
  45. 52 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorModule.cpp
  46. 64 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.cpp
  47. 42 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.h
  48. 14 14
      Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingConversionTest.cpp
  49. 12 0
      Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingTest.cpp
  50. 237 0
      Gems/LevelGeoreferencing/Code/Tests/Tools/GeoreferenceComponentTest.cpp
  51. 10 0
      Gems/LevelGeoreferencing/Code/georeferencing_api_files.cmake
  52. 8 0
      Gems/LevelGeoreferencing/Code/georeferencing_editor_api_files.cmake
  53. 11 0
      Gems/LevelGeoreferencing/Code/georeferencing_editor_private_files.cmake
  54. 8 0
      Gems/LevelGeoreferencing/Code/georeferencing_editor_shared_files.cmake
  55. 8 0
      Gems/LevelGeoreferencing/Code/georeferencing_editor_tests_files.cmake
  56. 18 0
      Gems/LevelGeoreferencing/Code/georeferencing_private_files.cmake
  57. 8 0
      Gems/LevelGeoreferencing/Code/georeferencing_shared_files.cmake
  58. 9 0
      Gems/LevelGeoreferencing/Code/georeferencing_tests_files.cmake
  59. 4 4
      Gems/LevelGeoreferencing/Registry/assetprocessor_settings.setreg
  60. 31 0
      Gems/LevelGeoreferencing/gem.json
  61. 3 0
      Gems/LevelGeoreferencing/preview.png
  62. 1 1
      Gems/MachineLearning/Code/CMakeLists.txt
  63. 4 3
      Gems/MachineLearning/gem.json
  64. 2 9
      Gems/OpenXRVk/3rdParty/Platform/Android/BuiltInPackages_android.cmake
  65. 0 42
      Gems/OpenXRVk/3rdParty/Platform/Android/FindOpenXROculus.cmake
  66. 2 2
      Gems/OpenXRVk/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake
  67. 0 7
      Gems/OpenXRVk/External/OculusOpenXRMobileSDK/README.md
  68. 2 2
      Gems/OpenXRVk/gem.json
  69. 0 18
      Gems/ProteusRobot/Assets/Materials/Proteus_chassis_Proteus.material
  70. 0 13
      Gems/ProteusRobot/Assets/Materials/Proteus_chassis_Side_Lights.material
  71. 0 19
      Gems/ProteusRobot/Assets/Materials/Proteus_chassis_wheel.material
  72. 0 3
      Gems/ProteusRobot/Assets/Proteus2_chassis.fbx
  73. 0 3
      Gems/ProteusRobot/Assets/Proteus2_lift.fbx
  74. 0 3
      Gems/ProteusRobot/Assets/Proteus_chassis.fbx
  75. 0 3
      Gems/ProteusRobot/Assets/Proteus_wheel.fbx
  76. 0 3
      Gems/ProteusRobot/Assets/Textures/Proteus_MaskMap.png
  77. 0 3
      Gems/ProteusRobot/Assets/Textures/Proteus_MaskMap_A.png
  78. 0 30
      Gems/ProteusRobot/README.md
  79. 0 35
      Gems/ProteusRobot/gem.json
  80. 0 3
      Gems/ProteusRobot/preview.png
  81. 0 3
      Gems/ROS2/Assets/Models/Sensors/Camera/CameraOrbbeck.fbx
  82. 0 3
      Gems/ROS2/Assets/Models/Sensors/LidarOS2/LidarOS2.fbx
  83. 0 3
      Gems/ROS2/Assets/Models/Sensors/LidarOS2/textures/AO_green.png
  84. 0 3
      Gems/ROS2/Assets/Models/Sensors/LidarOS2/textures/Smoothness.png
  85. 0 163
      Gems/ROS2/Assets/Prefabs/Sensors/CameraOrbbeck.prefab
  86. 29 4
      Gems/ROS2/Code/CMakeLists.txt
  87. 7 0
      Gems/ROS2/Code/Include/ROS2/Clock/ITimeSource.h
  88. 7 2
      Gems/ROS2/Code/Include/ROS2/Clock/ROS2Clock.h
  89. 6 0
      Gems/ROS2/Code/Include/ROS2/Clock/ROS2TimeSource.h
  90. 8 3
      Gems/ROS2/Code/Include/ROS2/Clock/RealTimeSource.h
  91. 6 0
      Gems/ROS2/Code/Include/ROS2/Clock/SimulationTimeSource.h
  92. 4 0
      Gems/ROS2/Code/Include/ROS2/Frame/ROS2FrameEditorComponent.h
  93. 0 51
      Gems/ROS2/Code/Include/ROS2/Georeference/GeoreferenceStructures.h
  94. 60 0
      Gems/ROS2/Code/Include/ROS2/Lidar/ClassSegmentationBus.h
  95. 14 29
      Gems/ROS2/Code/Include/ROS2/Lidar/LidarRaycasterBus.h
  96. 11 7
      Gems/ROS2/Code/Include/ROS2/Lidar/LidarRegistrarBus.h
  97. 229 0
      Gems/ROS2/Code/Include/ROS2/Lidar/RaycastResults.h
  98. 40 0
      Gems/ROS2/Code/Include/ROS2/Lidar/SegmentationClassConfiguration.h
  99. 22 0
      Gems/ROS2/Code/Include/ROS2/Lidar/SegmentationUtils.h
  100. 3 0
      Gems/ROS2/Code/Include/ROS2/ROS2Bus.h

+ 1 - 3
.gitattributes

@@ -124,11 +124,9 @@ Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Lucy/Lucy_low.fbx filter=lf
 Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Lucy/.wip/marmoset_bake.tbscene filter=lfs diff=lfs merge=lfs -text
 Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Lucy/.wip/Brass/brass_bake.spp filter=lfs diff=lfs merge=lfs -text
 Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Lucy/.wip/stone/stone_bake.spp filter=lfs diff=lfs merge=lfs -text
-Gems/ProteusRobot/docs/images/*.png filter= diff= merge= -text
-Gems/RosRobotSample/docs/images/*.png filter= diff= merge= -text
+Gems/ROS2SampleRobots/docs/images/*.png filter= diff= merge= -text
 Gems/WarehouseAutomation/docs/images/*.png filter= diff= merge= -text
 Gems/WarehouseAssets/docs/images/*.png filter= diff= merge= -text
-Gems/WarehouseSample/docs/images/*.png filter= diff= merge= -text
 Templates/Ros2FleetRobotTemplate/docs/images/*.png filter= diff= merge= -text
 Gems/ROS2/docs/**/*.png -filter -diff -merge
 Templates/Ros2ProjectTemplate/Screenshots/*.png filter= diff= merge= -text

+ 61 - 0
Gems/LevelGeoreferencing/.clang-format

@@ -0,0 +1,61 @@
+Language: Cpp
+
+AccessModifierOffset: -4
+AlignAfterOpenBracket: AlwaysBreak
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Right
+AlignOperands: false
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortFunctionsOnASingleLine: None
+AllowShortLambdasOnASingleLine: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: false
+BinPackParameters: false
+BreakBeforeBraces: Custom
+BraceWrapping:
+    AfterClass: true
+    AfterControlStatement: true
+    AfterEnum: true
+    AfterFunction: true
+    AfterNamespace: true
+    BeforeLambdaBody: true
+    AfterStruct: true
+    BeforeElse: true
+    SplitEmptyFunction: true
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeComma
+ColumnLimit: 140
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+FixNamespaceComments: true
+IncludeBlocks: Preserve
+IndentCaseBlocks: true
+IndentCaseLabels: false
+IndentPPDirectives: None
+IndentWidth: 4
+KeepEmptyLinesAtTheStartOfBlocks: false
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: All
+PenaltyReturnTypeOnItsOwnLine: 1000
+PointerAlignment: Left
+SortIncludes: true
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyParentheses: false
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+Standard: c++17
+UseTab: Never

+ 10 - 0
Gems/LevelGeoreferencing/CMakeLists.txt

@@ -0,0 +1,10 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+o3de_gem_setup("LevelGeoreferencing")
+
+ly_add_external_target_path(${CMAKE_CURRENT_SOURCE_DIR}/3rdParty)
+
+add_subdirectory(Code)

+ 257 - 0
Gems/LevelGeoreferencing/Code/CMakeLists.txt

@@ -0,0 +1,257 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR}
+# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}
+# Note: o3de_pal_dir will take care of the details for us, as this may be a restricted platform
+#       in which case it will see if that platform is present here or in the restricted folder.
+#       i.e. It could here in our gem : Gems/LevelGeoreferencing/Code/Platform/<platorm_name>  or
+#            <restricted_folder>/<platform_name>/Gems/LevelGeoreferencing/Code
+o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}")
+
+# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the
+# traits for this platform. Traits for a platform are defines for things like whether or not something in this gem
+# is supported by this platform.
+include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
+
+# Check to see if building the Gem Modules are supported for the current platform
+if(NOT PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED)
+    return()
+endif()
+
+# The ${gem_name}.API target declares the common interface that users of this gem should depend on in their targets
+ly_add_target(
+    NAME ${gem_name}.API INTERFACE
+    NAMESPACE Gem
+    FILES_CMAKE
+        georeferencing_api_files.cmake
+        ${pal_dir}/georeferencing_api_files.cmake
+    INCLUDE_DIRECTORIES
+        INTERFACE
+            Include
+    BUILD_DEPENDENCIES
+        INTERFACE
+           AZ::AzCore
+)
+
+# The ${gem_name}.Private.Object target is an internal target
+# It should not be used outside of this Gems CMakeLists.txt
+ly_add_target(
+    NAME ${gem_name}.Private.Object STATIC
+    NAMESPACE Gem
+    FILES_CMAKE
+        georeferencing_private_files.cmake
+        ${pal_dir}/georeferencing_private_files.cmake
+    TARGET_PROPERTIES
+        O3DE_PRIVATE_TARGET TRUE
+    INCLUDE_DIRECTORIES
+        PRIVATE
+            Include
+            Source
+    BUILD_DEPENDENCIES
+        PUBLIC
+            AZ::AzCore
+            AZ::AzFramework
+)
+
+# Here add ${gem_name} target, it depends on the Private Object library and Public API interface
+ly_add_target(
+    NAME ${gem_name} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
+    NAMESPACE Gem
+    FILES_CMAKE
+        georeferencing_shared_files.cmake
+        ${pal_dir}/georeferencing_shared_files.cmake
+    INCLUDE_DIRECTORIES
+        PUBLIC
+            Include
+        PRIVATE
+            Source
+    BUILD_DEPENDENCIES
+        PUBLIC
+            Gem::${gem_name}.API
+        PRIVATE
+            Gem::${gem_name}.Private.Object
+)
+
+# Include the gem name into the Client Module source file
+# for use with the AZ_DECLARE_MODULE_CLASS macro
+# This is to allow renaming of the gem to also cause
+# the CreateModuleClass_Gem_<gem-name> function which
+# is used to bootstrap the gem in monolithic builds to link to the new gem name
+ly_add_source_properties(
+SOURCES
+    Source/Clients/GeoreferencingModule.cpp
+PROPERTY COMPILE_DEFINITIONS
+    VALUES
+        O3DE_GEM_NAME=${gem_name}
+        O3DE_GEM_VERSION=${gem_version})
+
+# By default, we will specify that the above target ${gem_name} would be used by
+# Client and Server type targets when this gem is enabled.  If you don't want it
+# active in Clients or Servers by default, delete one of both of the following lines:
+ly_create_alias(NAME ${gem_name}.Clients NAMESPACE Gem TARGETS Gem::${gem_name})
+ly_create_alias(NAME ${gem_name}.Servers NAMESPACE Gem TARGETS Gem::${gem_name})
+ly_create_alias(NAME ${gem_name}.Unified NAMESPACE Gem TARGETS Gem::${gem_name})
+
+# For the Client and Server variants of ${gem_name} Gem, an alias to the ${gem_name}.API target will be made
+ly_create_alias(NAME ${gem_name}.Clients.API NAMESPACE Gem TARGETS Gem::${gem_name}.API)
+ly_create_alias(NAME ${gem_name}.Servers.API NAMESPACE Gem TARGETS Gem::${gem_name}.API)
+ly_create_alias(NAME ${gem_name}.Unified.API NAMESPACE Gem TARGETS Gem::${gem_name}.API)
+
+# Add in CMake dependencies for each gem dependency listed in this gem's gem.json file
+# for the Clients, Servers, Unified gem variants
+o3de_add_variant_dependencies_for_gem_dependencies(GEM_NAME ${gem_name} VARIANTS Clients Servers Unified)
+
+# If we are on a host platform, we want to add the host tools targets like the ${gem_name}.Editor MODULE target
+if(PAL_TRAIT_BUILD_HOST_TOOLS)
+    # The ${gem_name}.Editor.API target can be used by other gems that want to interact with the ${gem_name}.Editor module
+    ly_add_target(
+        NAME ${gem_name}.Editor.API INTERFACE
+        NAMESPACE Gem
+        FILES_CMAKE
+            georeferencing_editor_api_files.cmake
+            ${pal_dir}/georeferencing_editor_api_files.cmake
+        INCLUDE_DIRECTORIES
+            INTERFACE
+                Include
+        BUILD_DEPENDENCIES
+            INTERFACE
+                AZ::AzToolsFramework
+    )
+
+    # The ${gem_name}.Editor.Private.Object target is an internal target
+    # which is only to be used by this gems CMakeLists.txt and any subdirectories
+    # Other gems should not use this target
+    ly_add_target(
+        NAME ${gem_name}.Editor.Private.Object STATIC
+        NAMESPACE Gem
+        FILES_CMAKE
+            georeferencing_editor_private_files.cmake
+        TARGET_PROPERTIES
+            O3DE_PRIVATE_TARGET TRUE
+        INCLUDE_DIRECTORIES
+            PRIVATE
+                Include
+                Source
+        BUILD_DEPENDENCIES
+            PUBLIC
+                AZ::AzToolsFramework
+                ${gem_name}.Private.Object
+    )
+
+    ly_add_target(
+        NAME ${gem_name}.Editor GEM_MODULE
+        NAMESPACE Gem
+        AUTOMOC
+        FILES_CMAKE
+            georeferencing_editor_shared_files.cmake
+        INCLUDE_DIRECTORIES
+            PRIVATE
+                Source
+            PUBLIC
+                Include
+        BUILD_DEPENDENCIES
+            PUBLIC
+                Gem::${gem_name}.Editor.API
+            PRIVATE
+                Gem::${gem_name}.Editor.Private.Object
+    )
+
+    # Include the gem name into the Editor Module source file
+    # for use with the AZ_DECLARE_MODULE_CLASS macro
+    # This is to allow renaming of the gem to also cause
+    # the CreateModuleClass_Gem_<gem-name> function which
+    # is used to bootstrap the gem in monolithic builds to link to the new gem name
+    ly_add_source_properties(
+    SOURCES
+        Source/Tools/GeoreferencingEditorModule.cpp
+    PROPERTY COMPILE_DEFINITIONS
+        VALUES
+            O3DE_GEM_NAME=${gem_name}
+            O3DE_GEM_VERSION=${gem_version})
+
+    # By default, we will specify that the above target ${gem_name} would be used by
+    # Tool and Builder type targets when this gem is enabled.  If you don't want it
+    # active in Tools or Builders by default, delete one of both of the following lines:
+    ly_create_alias(NAME ${gem_name}.Tools    NAMESPACE Gem TARGETS Gem::${gem_name}.Editor)
+    ly_create_alias(NAME ${gem_name}.Builders NAMESPACE Gem TARGETS Gem::${gem_name}.Editor)
+
+    # For the Tools and Builders variants of ${gem_name} Gem, an alias to the ${gem_name}.Editor API target will be made
+    ly_create_alias(NAME ${gem_name}.Tools.API NAMESPACE Gem TARGETS Gem::${gem_name}.Editor.API)
+    ly_create_alias(NAME ${gem_name}.Builders.API NAMESPACE Gem TARGETS Gem::${gem_name}.Editor.API)
+
+    # Add in CMake dependencies for each gem dependency listed in this gem's gem.json file
+    # for the Tools and Builders gem variants
+    o3de_add_variant_dependencies_for_gem_dependencies(GEM_NAME ${gem_name} VARIANTS Tools Builders)
+endif()
+
+################################################################################
+# Tests
+################################################################################
+# See if globally, tests are supported
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
+    # We globally support tests, see if we support tests on this platform for ${gem_name}.Tests
+    if(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED)
+        # We support ${gem_name}.Tests on this platform, add dependency on the Private Object target
+        ly_add_target(
+            NAME ${gem_name}.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+            NAMESPACE Gem
+            FILES_CMAKE
+                georeferencing_tests_files.cmake
+            INCLUDE_DIRECTORIES
+                PRIVATE
+                    Tests
+                    Source
+                    Include
+            BUILD_DEPENDENCIES
+                PRIVATE
+                    AZ::AzTest
+                    AZ::AzFramework
+                    AZ::AzTestShared
+                    Gem::${gem_name}.Private.Object
+        )
+
+        # Add ${gem_name}.Tests to googletest
+        ly_add_googletest(
+            NAME Gem::${gem_name}.Tests
+        )
+    endif()
+
+    # If we are a host platform we want to add tools test like editor tests here
+    if(PAL_TRAIT_BUILD_HOST_TOOLS)
+        # We are a host platform, see if Editor tests are supported on this platform
+        if(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED)
+            # We support ${gem_name}.Editor.Tests on this platform, add ${gem_name}.Editor.Tests target which depends on
+            # private ${gem_name}.Editor.Private.Object target
+            ly_add_target(
+                NAME ${gem_name}.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+                NAMESPACE Gem
+                FILES_CMAKE
+                    georeferencing_editor_tests_files.cmake
+                INCLUDE_DIRECTORIES
+                    PRIVATE
+                        Tests
+                        Source
+                        Include
+                BUILD_DEPENDENCIES
+                    PRIVATE
+                        AZ::AzTest
+                        AZ::AzTestShared
+                        AZ::AzToolsFramework
+                        Legacy::CryCommon
+                        Legacy::EditorCommon
+                        Legacy::Editor.Headers
+                        AZ::AzManipulatorTestFramework.Static
+                        Gem::${gem_name}.API
+                        Gem::${gem_name}.Editor.Private.Object
+            )
+
+            # Add ${gem_name}.Editor.Tests to googletest
+            ly_add_googletest(
+                NAME Gem::${gem_name}.Editor.Tests
+            )
+        endif()
+    endif()
+endif()

+ 36 - 4
Gems/ROS2/Code/Include/ROS2/Georeference/GeoreferenceBus.h → Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceBus.h

@@ -8,17 +8,49 @@
 #pragma once
 
 #include "GeoreferenceStructures.h"
+#include "GeoreferencingTypeIds.h"
 #include <AzCore/Component/EntityId.h>
 #include <AzCore/EBus/EBus.h>
-#include <AzCore/Math/Vector3.h>
 #include <AzCore/Math/Quaternion.h>
+#include <AzCore/Math/Vector3.h>
 
-namespace ROS2
+namespace Georeferencing
 {
+
+    //! Interface that allows to configure georeferencing of the level.
+    class GeoreferenceConfigurationRequests
+    {
+    public:
+        AZ_RTTI(GeoreferenceConfigurationRequests, GeoreferenceConfigurationRequestsTypeId);
+
+        //! Function sets entity that represents the origin of the georeferencing.
+        virtual void SetOriginEntity(const AZ::EntityId& entityId) = 0;
+
+        //! Function sets location of the origin in WGS84 coordinate system.
+        virtual void SetOriginCoordinates(const WGS::WGS84Coordinate& origin) = 0;
+
+        //! Function returns entity that represents the origin of the georeferencing.
+        virtual AZ::EntityId GetOriginEntity() = 0;
+
+        //! Function returns location of the origin in WGS84 coordinate system.
+        virtual WGS::WGS84Coordinate GetOriginCoordinates() = 0;
+    };
+
+    class GeoreferenceConfigurationRequestsTraits : public AZ::EBusTraits
+    {
+    public:
+        // EBusTraits overrides ...
+        static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+    };
+
+    using GeoreferenceConfigurationRequestsBus = AZ::EBus<GeoreferenceConfigurationRequests, GeoreferenceConfigurationRequestsTraits>;
+
     //! Interface that allows to convert between level and WGS84 coordinates.
     class GeoreferenceRequests
     {
     public:
+        AZ_RTTI(GeoreferenceRequests, GeoreferenceRequestsTypeId);
 
         //! Function converts from Level's coordinate system to WGS84.
         //! @param xyz Vector3 in Level's coordinate system.
@@ -31,7 +63,7 @@ namespace ROS2
         virtual AZ::Vector3 ConvertFromWGS84ToLevel(const WGS::WGS84Coordinate& latLon) = 0;
 
         //! Function returns rotation from Level's frame to ENU's (East-North-Up) rotation.
-        //! Function is useful to fin georeference rotation of the level.
+        //! Function is useful to find georeferencing rotation of the level.
         //! @return Quaternion in ENU coordinate system.
         virtual AZ::Quaternion GetRotationFromLevelToENU() = 0;
     };
@@ -45,4 +77,4 @@ namespace ROS2
     };
 
     using GeoreferenceRequestsBus = AZ::EBus<GeoreferenceRequests, GeoreferenceRequestsTraits>;
-} // namespace ROS2
+} // namespace Georeferencing

+ 97 - 0
Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceStructures.h

@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root
+ * of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include "GeoreferencingTypeIds.h"
+#include <AzCore/Math/MathUtils.h>
+#include <AzCore/Math/Vector3.h>
+#include <AzCore/RTTI/RTTI.h>
+
+namespace Georeferencing::WGS
+{
+
+    //! WGS84Coordinate is a 3D vector with double precision.
+    //! It is used to represent coordinates in WGS84 coordinate system.
+    struct WGS84Coordinate
+    {
+        AZ_RTTI(WGS84Coordinate, WGS84CoordinateTypeId);
+        static void Reflect(AZ::ReflectContext* context);
+
+        WGS84Coordinate() = default;
+        virtual ~WGS84Coordinate() = default;
+
+        WGS84Coordinate(double latitude, double longitude, double altitude)
+            : m_latitude(latitude)
+            , m_longitude(longitude)
+            , m_altitude(altitude)
+        {
+        }
+
+        explicit WGS84Coordinate(const AZ::Vector3& latLonAlt)
+            : m_latitude(latLonAlt.GetX())
+            , m_longitude(latLonAlt.GetY())
+            , m_altitude(latLonAlt.GetZ())
+        {
+        }
+
+        void FromVector3f(const AZ::Vector3& latLonAlt)
+        {
+            m_latitude = latLonAlt.GetX();
+            m_longitude = latLonAlt.GetY();
+            m_altitude = latLonAlt.GetZ();
+        }
+
+        //! Converts WGS84Coordinate to Vector3f, where x is latitude, y is longitude
+        //! and z is altitude. Expect accuracy loss due to float conversion.
+        AZ::Vector3 ToVector3f() const
+        {
+            return AZ::Vector3(static_cast<float>(m_latitude), static_cast<float>(m_longitude), static_cast<float>(m_altitude));
+        }
+
+        bool operator==(const WGS84Coordinate& rhs) const
+        {
+            return AZ::IsClose(m_latitude, rhs.m_latitude) && AZ::IsClose(m_longitude, rhs.m_longitude) &&
+                AZ::IsClose(m_altitude, rhs.m_altitude);
+        }
+
+        void SetLatitude(double latitude)
+        {
+            m_latitude = latitude;
+        }
+
+        void SetLongitude(double longitude)
+        {
+            m_longitude = longitude;
+        }
+
+        void SetAltitude(double altitude)
+        {
+            m_altitude = altitude;
+        }
+
+        double GetLatitude() const
+        {
+            return m_latitude;
+        }
+
+        double GetLongitude() const
+        {
+            return m_longitude;
+        }
+        double GetAltitude() const
+        {
+            return m_altitude;
+        }
+
+        double m_latitude = 0.0; //!< Latitude in degrees.
+        double m_longitude = 0.0; //!< Longitude in degrees.
+        double m_altitude = 0.0; //!< Altitude in meters.
+    };
+} // namespace Georeferencing::WGS

+ 31 - 0
Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferencingTypeIds.h

@@ -0,0 +1,31 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+#pragma once
+
+namespace Georeferencing
+{
+    // System Component TypeIds
+    inline constexpr const char* GeoreferencingSystemComponentTypeId = "{41D42FB6-4C76-4400-8E39-68F8AAD4CB55}";
+    inline constexpr const char* GeoreferencingEditorSystemComponentTypeId = "{4D7E4975-EE64-4030-BEE0-671BF8CB8EC2}";
+
+    // Module derived classes TypeIds
+    inline constexpr const char* GeoreferencingModuleInterfaceTypeId = "{3F81E669-EA46-4C78-8596-040237413B02}";
+    inline constexpr const char* GeoreferencingModuleTypeId = "{0D488925-63E0-49BD-90A5-2CE96B7346FE}";
+    // The Editor Module by default is mutually exclusive with the Client Module
+    // so they use the Same TypeId
+    inline constexpr const char* GeoreferencingEditorModuleTypeId = GeoreferencingModuleTypeId;
+
+    inline constexpr const char* WGS84CoordinateTypeId = "{2E9FFFDC-0025-44EE-97B4-B42C0D59CAF9}";
+    inline constexpr const char* GeoreferenceRequestsTypeId = "{DD8F754A-D7A8-4DDD-8CBD-AA0F137DBF1D}";
+    inline constexpr const char* GeoreferenceConfigurationRequestsTypeId = "{AF78B7C1-2E9E-4955-BC2C-AB1F45C8186F}";
+    inline constexpr const char* GeoReferenceLevelEditorComponentTypeId = "{3A8789E8-3FA1-4A79-B262-02AF16379EAA}";
+    inline constexpr const char* GeoReferenceLevelComponentTypeId = "{711E912E-FF60-442F-9010-8503AD802246}";
+
+    inline constexpr const char* GeoReferenceLevelConfigTypeId = "{6C51A9EC-49E8-4344-9E3E-D2627C245FE1}";
+
+} // namespace Georeferencing

+ 8 - 0
Gems/LevelGeoreferencing/Code/Platform/Android/PAL_android.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED FALSE)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_private_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Android
+# i.e. ../Source/Android/GeoreferencingAndroid.cpp
+#      ../Source/Android/GeoreferencingAndroid.h
+#      ../Include/Android/GeoreferencingAndroid.h
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_shared_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Android
+# i.e. ../Source/Android/GeoreferencingAndroid.cpp
+#      ../Source/Android/GeoreferencingAndroid.h
+#      ../Include/Android/GeoreferencingAndroid.h
+
+set(FILES
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/Platform/Linux/PAL_linux.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED TRUE)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_editor_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_private_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Linux
+# i.e. ../Source/Linux/GeoreferencingLinux.cpp
+#      ../Source/Linux/GeoreferencingLinux.h
+#      ../Include/Linux/GeoreferencingLinux.h
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_shared_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Linux
+# i.e. ../Source/Linux/GeoreferencingLinux.cpp
+#      ../Source/Linux/GeoreferencingLinux.h
+#      ../Include/Linux/GeoreferencingLinux.h
+
+set(FILES
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/Platform/Mac/PAL_mac.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED FALSE)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_editor_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_private_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Mac
+# i.e. ../Source/Mac/GeoreferencingMac.cpp
+#      ../Source/Mac/GeoreferencingMac.h
+#      ../Include/Mac/GeoreferencingMac.h
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_shared_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Mac
+# i.e. ../Source/Mac/GeoreferencingMac.cpp
+#      ../Source/Mac/GeoreferencingMac.h
+#      ../Include/Mac/GeoreferencingMac.h
+
+set(FILES
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/Platform/Windows/PAL_windows.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED TRUE)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_editor_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_private_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Windows
+# i.e. ../Source/Windows/GeoreferencingWindows.cpp
+#      ../Source/Windows/GeoreferencingWindows.h
+#      ../Include/Windows/GeoreferencingWindows.h
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_shared_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for Windows
+# i.e. ../Source/Windows/GeoreferencingWindows.cpp
+#      ../Source/Windows/GeoreferencingWindows.h
+#      ../Include/Windows/GeoreferencingWindows.h
+
+set(FILES
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/Platform/iOS/PAL_ios.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(PAL_TRAIT_LEVELGEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_LEVELGEOREFERENCING_EDITOR_TEST_SUPPORTED FALSE)

+ 7 - 0
Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_api_files.cmake

@@ -0,0 +1,7 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_private_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for iOS
+# i.e. ../Source/iOS/GeoreferencingiOS.cpp
+#      ../Source/iOS/GeoreferencingiOS.h
+#      ../Include/iOS/GeoreferencingiOS.h
+
+set(FILES
+)

+ 12 - 0
Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_shared_files.cmake

@@ -0,0 +1,12 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+# Platform specific files for iOS
+# i.e. ../Source/iOS/GeoreferencingiOS.cpp
+#      ../Source/iOS/GeoreferencingiOS.h
+#      ../Include/iOS/GeoreferencingiOS.h
+
+set(FILES
+)

+ 3 - 3
Gems/ROS2/Code/Source/Georeference/GNSSFormatConversions.cpp → Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.cpp

@@ -6,7 +6,7 @@
  *
  */
 
-#include "Georeference/GNSSFormatConversions.h"
+#include "GNSSFormatConversions.h"
 
 constexpr double earthSemimajorAxis = 6378137.0;
 constexpr double reciprocalFlattening = 1.0 / 298.257223563;
@@ -16,7 +16,7 @@ constexpr double secondEccentrictySquared =
     reciprocalFlattening * (2.0 - reciprocalFlattening) / ((1.0 - reciprocalFlattening) * (1.0 - reciprocalFlattening));
 
 // Based on http://wiki.gis.com/wiki/index.php/Geodetic_system
-namespace ROS2::Utils::GeodeticConversions
+namespace Georeferencing::Utils::GeodeticConversions
 {
     inline double DegToRad(double degrees)
     {
@@ -110,4 +110,4 @@ namespace ROS2::Utils::GeodeticConversions
         return { RadToDeg(latitude), RadToDeg(longitude), altitude };
     }
 
-} // namespace ROS2::GNSS
+} // namespace Georeferencing::Utils::GeodeticConversions

+ 4 - 3
Gems/ROS2/Code/Source/Georeference/GNSSFormatConversions.h → Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.h

@@ -7,10 +7,11 @@
  */
 
 #pragma once
+#include "GeoreferenceInternalStructures.h"
 #include <AzCore/Math/Matrix4x4.h>
-#include <ROS2/Georeference/GeoreferenceStructures.h>
+#include <Georeferencing/GeoreferenceStructures.h>
 
-namespace ROS2::Utils::GeodeticConversions
+namespace Georeferencing::Utils::GeodeticConversions
 {
 
     //! Converts point in 1984 World Geodetic System (GS84) to Earth Centred Earth Fixed (ECEF)
@@ -40,4 +41,4 @@ namespace ROS2::Utils::GeodeticConversions
     //!     latitude and longitude are in decimal degrees
     //!     altitude is in meters
     WGS::WGS84Coordinate ECEFToWGS84(const WGS::Vector3d& ECFEPoint);
-} // namespace ROS2::Utils::GeodeticConversions
+} // namespace Georeferencing::Utils::GeodeticConversions

+ 50 - 0
Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.cpp

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root
+ * of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "GeoreferenceInternalStructures.h"
+
+namespace Georeferencing::WGS
+{
+
+    Vector3d::Vector3d(double x, double y, double z)
+        : m_x(x)
+        , m_y(y)
+        , m_z(z)
+    {
+    }
+    Vector3d::Vector3d(const AZ::Vector3& xyz)
+        : m_x(xyz.GetX())
+        , m_y(xyz.GetY())
+        , m_z(xyz.GetZ())
+    {
+    }
+    [[nodiscard]] AZ::Vector3 Vector3d::ToVector3f() const
+    {
+        return AZ::Vector3(static_cast<float>(m_x), static_cast<float>(m_y), static_cast<float>(m_z));
+    }
+
+    Vector3d Vector3d::operator+(Vector3d const& v) const
+    {
+        Vector3d r;
+        r.m_x = m_x + v.m_x;
+        r.m_y = m_y + v.m_y;
+        r.m_z = m_z + v.m_z;
+        return r;
+    }
+
+    Vector3d Vector3d::operator-(Vector3d const& v) const
+    {
+        Vector3d r;
+        r.m_x = m_x - v.m_x;
+        r.m_y = m_y - v.m_y;
+        r.m_z = m_z - v.m_z;
+        return r;
+    }
+
+} // namespace Georeferencing::WGS

+ 29 - 0
Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root
+ * of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+#include <AzCore/Math/Vector3.h>
+
+namespace Georeferencing::WGS
+{
+    //! Vector3d is a 3D vector with double precision.
+    //! It is used to represent coordinates in ECEF or ENU coordinate systems.
+    struct Vector3d
+    {
+        Vector3d() = default;
+        Vector3d(double x, double y, double z);
+        explicit Vector3d(const AZ::Vector3& xyz);
+        [[nodiscard]] AZ::Vector3 ToVector3f() const;
+        Vector3d operator+(Vector3d const& v) const;
+        Vector3d operator-(Vector3d const& v) const;
+        double m_x = 0.0; //!< X coordinate in meters.
+        double m_y = 0.0; //! Y coordinate in meters.
+        double m_z = 0.0; //! Z coordinate in meters.
+    };
+} // namespace Georeferencing::WGS

+ 68 - 9
Gems/ROS2/Code/Source/Georeference/GeoreferenceLevelComponent.cpp → Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.cpp

@@ -8,17 +8,17 @@
 
 #include "GeoreferenceLevelComponent.h"
 #include "GNSSFormatConversions.h"
+#include "GeoreferenceInternalStructures.h"
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/Math/Matrix4x4.h>
+#include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/Serialization/EditContext.h>
 #include <AzCore/Serialization/SerializeContext.h>
-#include <ROS2/Georeference/GeoreferenceStructures.h>
-
-namespace ROS2
+#include <Georeferencing/GeoreferenceStructures.h>
+namespace Georeferencing
 {
     void GeoReferenceLevelConfig::Reflect(AZ::ReflectContext* context)
     {
-        WGS::WGS84Coordinate::Reflect(context);
         if (auto* serialize = azrtti_cast<AZ::SerializeContext*>(context))
         {
             serialize->Class<GeoReferenceLevelConfig, AZ::ComponentConfig>()
@@ -42,6 +42,16 @@ namespace ROS2
                         "ENU Origin Coordinates in WGS84");
             }
         }
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->EBus<GeoreferenceRequestsBus>("GeoreferenceRequestsBus")
+                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+                ->Attribute(AZ::Script::Attributes::Category, "GeoreferenceRequests")
+                ->Attribute(AZ::Script::Attributes::Module, "GeoreferenceRequests")
+                ->Event("ConvertFromLevelToWGS84", &GeoreferenceRequests::ConvertFromLevelToWGS84)
+                ->Event("ConvertFromWGS84ToLevel", &GeoreferenceRequests::ConvertFromWGS84ToLevel)
+                ->Event("GetRotationFromLevelToENU", &GeoreferenceRequests::GetRotationFromLevelToENU);
+        }
     }
 
     void GeoReferenceLevelController::Reflect(AZ::ReflectContext* context)
@@ -57,7 +67,7 @@ namespace ROS2
             if (editContext)
             {
                 editContext->Class<GeoReferenceLevelController>("GeoReferenceLevelController", "Controller for GeoReferenceLevelComponent")
-                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "Manages spawning of robots in configurable locations")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "Manages Georeferencing of the level")
                     ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
                     ->DataElement(AZ::Edit::UIHandlers::Default, &GeoReferenceLevelController::m_config);
             }
@@ -75,26 +85,42 @@ namespace ROS2
     void GeoReferenceLevelController::Activate(AZ::EntityId entityId)
     {
         AZ::EntityBus::Handler::BusConnect(m_config.m_enuOriginLocationEntityId);
+        AZ::TransformNotificationBus::Handler::BusConnect(m_config.m_enuOriginLocationEntityId);
         GeoreferenceRequestsBus::Handler::BusConnect();
+        GeoreferenceConfigurationRequestsBus::Handler::BusConnect();
     }
 
     void GeoReferenceLevelController::Deactivate()
     {
+        GeoreferenceConfigurationRequestsBus::Handler::BusDisconnect();
         GeoreferenceRequestsBus::Handler::BusDisconnect();
+        AZ::TransformNotificationBus::Handler::BusDisconnect();
         AZ::EntityBus::Handler::BusDisconnect();
     }
 
     void GeoReferenceLevelController::OnEntityActivated(const AZ::EntityId& entityId)
     {
+        AZ_Assert(entityId == m_config.m_enuOriginLocationEntityId, "Entity activated is not the origin entity");
         m_enuOriginTransform = AZ::Transform::CreateIdentity();
         AZ::TransformBus::EventResult(m_enuOriginTransform, m_config.m_enuOriginLocationEntityId, &AZ::TransformBus::Events::GetWorldTM);
         m_enuOriginTransform.Invert();
+        AZ::TransformNotificationBus::Handler::BusConnect(m_config.m_enuOriginLocationEntityId);
         AZ::EntityBus::Handler::BusDisconnect();
     }
 
+    void GeoReferenceLevelController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
+    {
+        ApplyOriginTransform(world);
+    }
+
+    void GeoReferenceLevelController::ApplyOriginTransform(const AZ::Transform& worldTransform)
+    {
+        m_enuOriginTransform = worldTransform.GetInverse();
+    }
+
     WGS::WGS84Coordinate GeoReferenceLevelController::ConvertFromLevelToWGS84(const AZ::Vector3& xyz)
     {
-        using namespace ROS2::Utils::GeodeticConversions;
+        using namespace Georeferencing::Utils::GeodeticConversions;
         const auto enu = WGS::Vector3d(m_enuOriginTransform.TransformPoint(xyz));
         const auto ecef = ENUToECEF(m_config.m_originLocation, enu);
         return ECEFToWGS84(ecef);
@@ -102,7 +128,7 @@ namespace ROS2
 
     AZ::Vector3 GeoReferenceLevelController::ConvertFromWGS84ToLevel(const WGS::WGS84Coordinate& latLon)
     {
-        using namespace ROS2::Utils::GeodeticConversions;
+        using namespace Georeferencing::Utils::GeodeticConversions;
         const auto ecef = WGS84ToECEF(latLon);
         const auto enu = ECEFToENU(m_config.m_originLocation, ecef);
         return m_enuOriginTransform.GetInverse().TransformPoint(enu.ToVector3f());
@@ -116,6 +142,40 @@ namespace ROS2
     void GeoReferenceLevelController::SetConfiguration(const GeoReferenceLevelConfig& config)
     {
         m_config = config;
+        SetOriginEntity(m_config.m_enuOriginLocationEntityId);
+    }
+
+    void GeoReferenceLevelController::SetOriginEntity(const AZ::EntityId& entityId)
+    {
+        m_config.m_enuOriginLocationEntityId = entityId;
+        AZ::Transform transform = AZ::Transform::CreateIdentity();
+        AZ::TransformBus::EventResult(transform, m_config.m_enuOriginLocationEntityId, &AZ::TransformBus::Events::GetWorldTM);
+        ApplyOriginTransform(transform);
+        if (AZ::EntityBus::Handler::BusIsConnected())
+        {
+            AZ::EntityBus::Handler::BusDisconnect();
+        }
+        if (AZ::TransformNotificationBus::Handler::BusIsConnected())
+        {
+            AZ::TransformNotificationBus::Handler::BusDisconnect();
+        }
+        AZ::EntityBus::Handler::BusConnect(m_config.m_enuOriginLocationEntityId);
+        AZ::TransformNotificationBus::Handler::BusConnect(m_config.m_enuOriginLocationEntityId);
+    }
+
+    void GeoReferenceLevelController::SetOriginCoordinates(const WGS::WGS84Coordinate& origin)
+    {
+        m_config.m_originLocation = origin;
+    }
+
+    AZ::EntityId GeoReferenceLevelController::GetOriginEntity()
+    {
+        return m_config.m_enuOriginLocationEntityId;
+    }
+
+    WGS::WGS84Coordinate GeoReferenceLevelController::GetOriginCoordinates()
+    {
+        return m_config.m_originLocation;
     }
 
     const GeoReferenceLevelConfig& GeoReferenceLevelController::GetConfiguration() const
@@ -147,5 +207,4 @@ namespace ROS2
     {
         GeoReferenceLevelComponentBase::Deactivate();
     }
-
-} // namespace ROS2
+} // namespace Georeferencing

+ 20 - 5
Gems/ROS2/Code/Source/Georeference/GeoreferenceLevelComponent.h → Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.h

@@ -5,19 +5,21 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
+
 #pragma once
 #include <AzCore/Component/Component.h>
 #include <AzCore/Component/EntityBus.h>
+#include <AzCore/Component/TransformBus.h>
 #include <AzCore/Math/Transform.h>
 #include <AzCore/Serialization/SerializeContext.h>
 #include <AzFramework/Components/ComponentAdapter.h>
-#include <ROS2/Georeference/GeoreferenceBus.h>
+#include <Georeferencing/GeoreferenceBus.h>
 
-namespace ROS2
+namespace Georeferencing
 {
     struct GeoReferenceLevelConfig : public AZ::ComponentConfig
     {
-        AZ_RTTI(GeoReferenceLevelConfig, "{22866de2-2d34-4510-988d-9f55a07a64c3}", AZ::ComponentConfig);
+        AZ_RTTI(GeoReferenceLevelConfig, GeoReferenceLevelConfigTypeId, AZ::ComponentConfig);
 
         static void Reflect(AZ::ReflectContext* context);
 
@@ -27,7 +29,9 @@ namespace ROS2
 
     class GeoReferenceLevelController
         : private GeoreferenceRequestsBus::Handler
+        , private GeoreferenceConfigurationRequestsBus::Handler
         , private AZ::EntityBus::Handler
+        , private AZ::TransformNotificationBus::Handler
     {
     public:
         AZ_TYPE_INFO(GeoReferenceLevelController, "{60b22daa-c241-49d2-ba83-dca380c179b1}");
@@ -53,6 +57,17 @@ namespace ROS2
         AZ::Vector3 ConvertFromWGS84ToLevel(const WGS::WGS84Coordinate& latLon) override;
         AZ::Quaternion GetRotationFromLevelToENU() override;
 
+        // ConfigurationRequestsBus::Handler overrides ...
+        void SetOriginEntity(const AZ::EntityId& entityId) override;
+        void SetOriginCoordinates(const WGS::WGS84Coordinate& origin) override;
+        AZ::EntityId GetOriginEntity() override;
+        WGS::WGS84Coordinate GetOriginCoordinates() override;
+
+        // TransformNotificationBus::Handler overrides ...
+        void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
+
+        void ApplyOriginTransform(const AZ::Transform& worldTransform);
+
         GeoReferenceLevelConfig m_config;
         AZ::Transform m_enuOriginTransform; //!< Transform of the entity that lays in the origin of the ENU coordinate system
     };
@@ -62,7 +77,7 @@ namespace ROS2
     class GeoReferenceLevelComponent : public GeoReferenceLevelComponentBase
     {
     public:
-        AZ_COMPONENT(GeoReferenceLevelComponent, "{7dcd0112-db23-41b8-90b8-4c66c6a197e4}", AZ::Component);
+        AZ_COMPONENT(GeoReferenceLevelComponent, GeoReferenceLevelComponentTypeId, AZ::Component);
         static void Reflect(AZ::ReflectContext* context);
 
         GeoReferenceLevelComponent(const GeoReferenceLevelConfig& config);
@@ -74,4 +89,4 @@ namespace ROS2
         void Deactivate() override;
     };
 
-} // namespace ROS2
+} // namespace Georeferencing

+ 19 - 67
Gems/ROS2/Code/Source/Georeference/GeoreferenceStructures.cpp → Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceStructures.cpp

@@ -7,34 +7,13 @@
  */
 
 #include <AzCore/Math/Vector3.h>
+#include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/Serialization/EditContext.h>
 #include <AzCore/Serialization/SerializeContext.h>
-#include <ROS2/Georeference/GeoreferenceStructures.h>
+#include <Georeferencing/GeoreferenceStructures.h>
 
-namespace ROS2::WGS
+namespace Georeferencing::WGS
 {
-
-    WGS84Coordinate::WGS84Coordinate()
-        : m_latitude(0.0)
-        , m_longitude(0.0)
-        , m_altitude(0.0)
-    {
-    }
-
-    WGS84Coordinate::WGS84Coordinate(double latitude, double longitude, double altitude)
-        : m_latitude(latitude)
-        , m_longitude(longitude)
-        , m_altitude(altitude)
-    {
-    }
-
-    WGS84Coordinate::WGS84Coordinate(const AZ::Vector3& latLonAlt)
-        : m_latitude(latLonAlt.GetX())
-        , m_longitude(latLonAlt.GetY())
-        , m_altitude(latLonAlt.GetZ())
-    {
-    }
-
     void WGS84Coordinate::Reflect(AZ::ReflectContext* context)
     {
         if (auto* serialize = azrtti_cast<AZ::SerializeContext*>(context))
@@ -62,48 +41,21 @@ namespace ROS2::WGS
                         AZ::Edit::UIHandlers::Default, &WGS84Coordinate::m_altitude, "Altitude", "Altitude in meters, WGS84 ellipsoid");
             }
         }
+        if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<WGS84Coordinate>("WGS84Coordinate")
+                ->Constructor<>()
+                ->Constructor<double, double, double>()
+                ->Attribute(AZ::Script::Attributes::Category, "Georeferencing")
+                ->Method("ToVector3f", &WGS84Coordinate::ToVector3f)
+                ->Method("FromVector3f", &WGS84Coordinate::FromVector3f)
+                ->Method("SetLatitude", &WGS84Coordinate::SetLatitude)
+                ->Method("SetLongitude", &WGS84Coordinate::SetLongitude)
+                ->Method("SetAltitude", &WGS84Coordinate::SetAltitude)
+                ->Method("GetLatitude", &WGS84Coordinate::GetLatitude)
+                ->Method("GetLongitude", &WGS84Coordinate::GetLongitude)
+                ->Method("GetAltitude", &WGS84Coordinate::GetAltitude);
+        }
     }
 
-    AZ::Vector3 WGS84Coordinate::ToVector3f() const
-    {
-        return AZ::Vector3(static_cast<float>(m_latitude), static_cast<float>(m_longitude), static_cast<float>(m_altitude));
-    }
-
-    Vector3d::Vector3d(double x, double y, double z)
-        : m_x(x)
-        , m_y(y)
-        , m_z(z)
-    {
-    }
-
-    [[maybe_unused]] Vector3d::Vector3d(const AZ::Vector3& xyz)
-        : m_x(xyz.GetX())
-        , m_y(xyz.GetY())
-        , m_z(xyz.GetZ())
-    {
-    }
-
-    AZ::Vector3 Vector3d::ToVector3f() const
-    {
-        return AZ::Vector3(static_cast<float>(m_x), static_cast<float>(m_y), static_cast<float>(m_z));
-    }
-
-    Vector3d Vector3d::operator+(Vector3d const& v) const
-    {
-        Vector3d r;
-        r.m_x = m_x + v.m_x;
-        r.m_y = m_y + v.m_y;
-        r.m_z = m_z + v.m_z;
-        return r;
-    }
-
-    Vector3d Vector3d::operator-(Vector3d const& v) const
-    {
-        Vector3d r;
-        r.m_x = m_x - v.m_x;
-        r.m_y = m_y - v.m_y;
-        r.m_z = m_z - v.m_z;
-        return r;
-    }
-
-} // namespace ROS2::WGS
+} // namespace Georeferencing::WGS

+ 26 - 0
Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingModule.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "GeoreferencingSystemComponent.h"
+#include <Georeferencing/GeoreferencingTypeIds.h>
+#include <GeoreferencingModuleInterface.h>
+namespace Georeferencing
+{
+    class GeoreferencingModule : public GeoreferencingModuleInterface
+    {
+    public:
+        AZ_RTTI(GeoreferencingModule, GeoreferencingModuleTypeId, GeoreferencingModuleInterface);
+        AZ_CLASS_ALLOCATOR(GeoreferencingModule, AZ::SystemAllocator);
+    };
+} // namespace Georeferencing
+
+#if defined(O3DE_GEM_NAME)
+AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME), Georeferencing::GeoreferencingModule)
+#else
+AZ_DECLARE_MODULE_CLASS(Gem_LevelGeoreferencing, Georeferencing::GeoreferencingModule)
+#endif

+ 58 - 0
Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.cpp

@@ -0,0 +1,58 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#include "GeoreferencingSystemComponent.h"
+
+#include <Georeferencing/GeoreferencingTypeIds.h>
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <Georeferencing/GeoreferenceStructures.h>
+namespace Georeferencing
+{
+    AZ_COMPONENT_IMPL(GeoreferencingSystemComponent, "GeoreferencingSystemComponent", GeoreferencingSystemComponentTypeId);
+
+    void GeoreferencingSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        WGS::WGS84Coordinate::Reflect(context);
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<GeoreferencingSystemComponent, AZ::Component>()->Version(0);
+        }
+    }
+
+    void GeoreferencingSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("GeoreferencingService"));
+    }
+
+    void GeoreferencingSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("GeoreferencingService"));
+    }
+
+    void GeoreferencingSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+    }
+
+    void GeoreferencingSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+    }
+
+    void GeoreferencingSystemComponent::Init()
+    {
+    }
+
+    void GeoreferencingSystemComponent::Activate()
+    {
+    }
+
+    void GeoreferencingSystemComponent::Deactivate()
+    {
+    }
+
+} // namespace Georeferencing

+ 38 - 0
Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.h

@@ -0,0 +1,38 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TickBus.h>
+
+namespace Georeferencing
+{
+    class GeoreferencingSystemComponent : public AZ::Component
+    {
+    public:
+        AZ_COMPONENT_DECL(GeoreferencingSystemComponent);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+        GeoreferencingSystemComponent() = default;
+        ~GeoreferencingSystemComponent() = default;
+
+    protected:
+        // AZ::Component interface implementation
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+    };
+
+} // namespace Georeferencing

+ 42 - 0
Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.cpp

@@ -0,0 +1,42 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#include "GeoreferencingModuleInterface.h"
+#include <AzCore/Memory/Memory.h>
+
+#include <Georeferencing/GeoreferencingTypeIds.h>
+
+#include <Clients/GeoreferenceLevelComponent.h>
+#include <Clients/GeoreferencingSystemComponent.h>
+namespace Georeferencing
+{
+    AZ_TYPE_INFO_WITH_NAME_IMPL(GeoreferencingModuleInterface, "GeoreferencingModuleInterface", GeoreferencingModuleInterfaceTypeId);
+    AZ_RTTI_NO_TYPE_INFO_IMPL(GeoreferencingModuleInterface, AZ::Module);
+    AZ_CLASS_ALLOCATOR_IMPL(GeoreferencingModuleInterface, AZ::SystemAllocator);
+
+    GeoreferencingModuleInterface::GeoreferencingModuleInterface()
+    {
+        // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
+        // Add ALL components descriptors associated with this gem to m_descriptors.
+        // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext.
+        // This happens through the [MyComponent]::Reflect() function.
+        m_descriptors.insert(
+            m_descriptors.end(),
+            {
+                GeoreferencingSystemComponent::CreateDescriptor(),
+                GeoReferenceLevelComponent::CreateDescriptor(),
+            });
+    }
+
+    AZ::ComponentTypeList GeoreferencingModuleInterface::GetRequiredSystemComponents() const
+    {
+        return AZ::ComponentTypeList{
+            azrtti_typeid<GeoreferencingSystemComponent>(),
+        };
+    }
+} // namespace Georeferencing

+ 30 - 0
Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.h

@@ -0,0 +1,30 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#include <AzCore/Memory/Memory_fwd.h>
+#include <AzCore/Module/Module.h>
+#include <AzCore/RTTI/RTTIMacros.h>
+#include <AzCore/RTTI/TypeInfoSimple.h>
+
+namespace Georeferencing
+{
+    class GeoreferencingModuleInterface : public AZ::Module
+    {
+    public:
+        AZ_TYPE_INFO_WITH_NAME_DECL(GeoreferencingModuleInterface)
+        AZ_RTTI_NO_TYPE_INFO_DECL()
+        AZ_CLASS_ALLOCATOR_DECL
+
+        GeoreferencingModuleInterface();
+
+        /**
+         * Add required SystemComponents to the SystemEntity.
+         */
+        AZ::ComponentTypeList GetRequiredSystemComponents() const override;
+    };
+} // namespace Georeferencing

+ 4 - 3
Gems/ROS2/Code/Source/Georeference/GeoreferenceLevelEditorComponent.cpp → Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.cpp

@@ -5,9 +5,10 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
+
 #include "GeoreferenceLevelEditorComponent.h"
 
-namespace ROS2
+namespace Georeferencing
 {
 
     GeoReferenceLevelEditorComponent::GeoReferenceLevelEditorComponent(const GeoReferenceLevelConfig& configuration)
@@ -31,7 +32,7 @@ namespace ROS2
                     ->Class<GeoReferenceLevelEditorComponent>(
                         "GeoReference Level Editor Component", "Component allows to provide georeference level for the level")
                     ->ClassElement(AZ::Edit::ClassElements::EditorData, "Component allows to provide georeference level for the level")
-                    ->Attribute(AZ::Edit::Attributes::Category, "ROS2")
+                    ->Attribute(AZ::Edit::Attributes::Category, "Georeferencing")
                     ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Level"))
                     ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/ROS2GNSSSensor.svg")
                     ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/ROS2GNSSSensor.svg")
@@ -54,4 +55,4 @@ namespace ROS2
         return true;
     };
 
-} // namespace ROS2
+} // namespace Georeferencing

+ 12 - 14
Gems/ROS2/Code/Source/Georeference/GeoreferenceLevelEditorComponent.h → Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.h

@@ -1,39 +1,37 @@
 /*
-* Copyright (c) Contributors to the Open 3D Engine Project.
-* For complete copyright and license terms please see the LICENSE at the root of this distribution.
-*
-* SPDX-License-Identifier: Apache-2.0 OR MIT
-*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
  */
+
 #pragma once
 
 #include <AzCore/Component/Component.h>
+#include <Georeferencing/GeoreferencingTypeIds.h>
 
-#include "GeoreferenceLevelComponent.h"
+#include "Clients/GeoreferenceLevelComponent.h"
 #include <AzToolsFramework/ToolsComponents/EditorComponentAdapter.h>
 #include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
 
-
-namespace ROS2
+namespace Georeferencing
 {
     using GeoReferenceLevelEditorComponentBase = AzToolsFramework::Components::
         EditorComponentAdapter<GeoReferenceLevelController, GeoReferenceLevelComponent, GeoReferenceLevelConfig>;
 
-    class GeoReferenceLevelEditorComponent
-        : public GeoReferenceLevelEditorComponentBase
+    class GeoReferenceLevelEditorComponent : public GeoReferenceLevelEditorComponentBase
     {
     public:
         GeoReferenceLevelEditorComponent() = default;
         explicit GeoReferenceLevelEditorComponent(const GeoReferenceLevelConfig& configuration);
 
-        AZ_EDITOR_COMPONENT(GeoReferenceLevelEditorComponent, "{b2c22304-d414-455c-808b-290142e59af0}", GeoReferenceLevelEditorComponentBase);
+        AZ_EDITOR_COMPONENT(GeoReferenceLevelEditorComponent, GeoReferenceLevelEditorComponentTypeId, GeoReferenceLevelEditorComponentBase);
         static void Reflect(AZ::ReflectContext* context);
 
         // GeoReferenceLevelEditorComponentBase interface overrides...
         void Activate() override;
         void Deactivate() override;
         bool ShouldActivateController() const override;
-
-
     };
-} // namespace ROS2
+} // namespace Georeferencing

+ 52 - 0
Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorModule.cpp

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "GeoreferenceLevelEditorComponent.h"
+#include "GeoreferencingEditorSystemComponent.h"
+#include <Georeferencing/GeoreferencingTypeIds.h>
+#include <GeoreferencingModuleInterface.h>
+namespace Georeferencing
+{
+    class GeoreferencingEditorModule : public GeoreferencingModuleInterface
+    {
+    public:
+        AZ_RTTI(GeoreferencingEditorModule, GeoreferencingEditorModuleTypeId, GeoreferencingModuleInterface);
+        AZ_CLASS_ALLOCATOR(GeoreferencingEditorModule, AZ::SystemAllocator);
+
+        GeoreferencingEditorModule()
+        {
+            // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
+            // Add ALL components descriptors associated with this gem to m_descriptors.
+            // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and
+            // EditContext. This happens through the [MyComponent]::Reflect() function.
+            m_descriptors.insert(
+                m_descriptors.end(),
+                {
+                    GeoreferencingEditorSystemComponent::CreateDescriptor(),
+                    GeoReferenceLevelEditorComponent::CreateDescriptor(),
+                });
+        }
+
+        /**
+         * Add required SystemComponents to the SystemEntity.
+         * Non-SystemComponents should not be added here
+         */
+        AZ::ComponentTypeList GetRequiredSystemComponents() const override
+        {
+            return AZ::ComponentTypeList{
+                azrtti_typeid<GeoreferencingEditorSystemComponent>(),
+            };
+        }
+    };
+} // namespace Georeferencing
+
+#if defined(O3DE_GEM_NAME)
+AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME, _Editor), Georeferencing::GeoreferencingEditorModule)
+#else
+AZ_DECLARE_MODULE_CLASS(Gem_LevelGeoreferencing_Editor, Georeferencing::GeoreferencingEditorModule)
+#endif

+ 64 - 0
Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.cpp

@@ -0,0 +1,64 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#include "GeoreferencingEditorSystemComponent.h"
+#include <AzCore/Serialization/SerializeContext.h>
+
+#include <Georeferencing/GeoreferencingTypeIds.h>
+
+namespace Georeferencing
+{
+    AZ_COMPONENT_IMPL(
+        GeoreferencingEditorSystemComponent,
+        "GeoreferencingEditorSystemComponent",
+        GeoreferencingEditorSystemComponentTypeId,
+        BaseSystemComponent);
+
+    void GeoreferencingEditorSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<GeoreferencingEditorSystemComponent, GeoreferencingSystemComponent>()->Version(0);
+        }
+    }
+
+    void GeoreferencingEditorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        BaseSystemComponent::GetProvidedServices(provided);
+        provided.push_back(AZ_CRC_CE("GeoreferencingEditorService"));
+    }
+
+    void GeoreferencingEditorSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        BaseSystemComponent::GetIncompatibleServices(incompatible);
+        incompatible.push_back(AZ_CRC_CE("GeoreferencingEditorService"));
+    }
+
+    void GeoreferencingEditorSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        BaseSystemComponent::GetRequiredServices(required);
+    }
+
+    void GeoreferencingEditorSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+        BaseSystemComponent::GetDependentServices(dependent);
+    }
+
+    void GeoreferencingEditorSystemComponent::Activate()
+    {
+        GeoreferencingSystemComponent::Activate();
+        AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
+    }
+
+    void GeoreferencingEditorSystemComponent::Deactivate()
+    {
+        AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
+        GeoreferencingSystemComponent::Deactivate();
+    }
+
+} // namespace Georeferencing

+ 42 - 0
Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.h

@@ -0,0 +1,42 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+#pragma once
+
+#include <AzToolsFramework/API/ToolsApplicationAPI.h>
+
+#include <Clients/GeoreferencingSystemComponent.h>
+
+namespace Georeferencing
+{
+    /// System component for Georeferencing editor
+    class GeoreferencingEditorSystemComponent
+        : public GeoreferencingSystemComponent
+        , protected AzToolsFramework::EditorEvents::Bus::Handler
+    {
+        using BaseSystemComponent = GeoreferencingSystemComponent;
+
+    public:
+        AZ_COMPONENT_DECL(GeoreferencingEditorSystemComponent);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        GeoreferencingEditorSystemComponent() = default;
+        ~GeoreferencingEditorSystemComponent() override = default;
+
+    private:
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+        // AZ::Component
+        void Activate() override;
+        void Deactivate() override;
+    };
+} // namespace Georeferencing

+ 14 - 14
Gems/ROS2/Code/Tests/GNSSTest.cpp → Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingConversionTest.cpp

@@ -9,21 +9,21 @@
 #include <AzCore/UnitTest/TestTypes.h>
 #include <AzTest/AzTest.h>
 
-#include <Georeference/GNSSFormatConversions.h>
+#include "Clients/GNSSFormatConversions.h"
 
 namespace UnitTest
 {
 
-    class GNSSTest : public LeakDetectionFixture
+    class GeoreferencingConversionTest : public LeakDetectionFixture
     {
     };
 
     constexpr double OneMillimiter = 0.001; // 1 mm in meters
     constexpr double OneMillimeterInDegreesOnEquator = 360.0 / (40000.0 * 1000.0 / OneMillimiter); // 40000 km is the equator length
 
-    TEST_F(GNSSTest, WGS84ToECEF)
+    TEST_F(GeoreferencingConversionTest, WGS84ToECEF)
     {
-        using namespace ROS2::WGS;
+        using namespace Georeferencing::WGS;
         const AZStd::vector<AZStd::pair<WGS84Coordinate, Vector3d>> inputGoldSet = {
             { { 10.0, 20.0, 300.0 }, { 5903307.167667380, 2148628.092761247, 1100300.642188661 } },
             { { -70.0, 170.0, 500.0 }, { -2154856.524084172, 379959.3447517005, -5971509.853428957 } },
@@ -31,16 +31,16 @@ namespace UnitTest
         };
         for (const auto& [input, goldResult] : inputGoldSet)
         {
-            const auto result = ROS2::Utils::GeodeticConversions::WGS84ToECEF(input);
+            const auto result = Georeferencing::Utils::GeodeticConversions::WGS84ToECEF(input);
             EXPECT_NEAR(result.m_x, goldResult.m_x, OneMillimiter);
             EXPECT_NEAR(result.m_y, goldResult.m_y, OneMillimiter);
             EXPECT_NEAR(result.m_z, goldResult.m_z, OneMillimiter);
         }
     }
 
-    TEST_F(GNSSTest, ECEFToENU)
+    TEST_F(GeoreferencingConversionTest, ECEFToENU)
     {
-        using namespace ROS2::WGS;
+        using namespace Georeferencing::WGS;
         const AZStd::vector<AZStd::tuple<Vector3d, WGS84Coordinate, Vector3d>> inputGoldSet = {
             { { -2053900.0, -3557459.0, 4862712.0 }, { 50.0, -120.0, -100.0 }, { -0.076833, -0.3202, -0.2969 } },
             { { 5903307.167667380, 2148628.092761247, 1100300.642188661 },
@@ -52,16 +52,16 @@ namespace UnitTest
         };
         for (const auto& [input, refWGS84, goldResult] : inputGoldSet)
         {
-            const auto result = ROS2::Utils::GeodeticConversions::ECEFToENU(refWGS84, input);
+            const auto result = Georeferencing::Utils::GeodeticConversions::ECEFToENU(refWGS84, input);
             EXPECT_NEAR(result.m_x, goldResult.m_x, OneMillimiter);
             EXPECT_NEAR(result.m_y, goldResult.m_y, OneMillimiter);
             EXPECT_NEAR(result.m_z, goldResult.m_z, OneMillimiter);
         }
     }
 
-    TEST_F(GNSSTest, ENUToECEF)
+    TEST_F(GeoreferencingConversionTest, ENUToECEF)
     {
-        using namespace ROS2::WGS;
+        using namespace Georeferencing::WGS;
         const AZStd::vector<AZStd::tuple<Vector3d, WGS84Coordinate, Vector3d>> inputGoldSet = {
             { { -0.076833, -0.3202, -0.2969 }, { 50.0, -120.0, -100.0 }, { -2053900.0, -3557459.0, 4862712.0 } },
             { { -109638.9539891188, -110428.2398398574, -2004.501240225796 },
@@ -73,16 +73,16 @@ namespace UnitTest
         };
         for (const auto& [input, refWGS84, goldResult] : inputGoldSet)
         {
-            const auto result = ROS2::Utils::GeodeticConversions::ENUToECEF(refWGS84, input);
+            const auto result = Georeferencing::Utils::GeodeticConversions::ENUToECEF(refWGS84, input);
             EXPECT_NEAR(result.m_x, goldResult.m_x, OneMillimiter);
             EXPECT_NEAR(result.m_y, goldResult.m_y, OneMillimiter);
             EXPECT_NEAR(result.m_z, goldResult.m_z, OneMillimiter);
         }
     }
 
-    TEST_F(GNSSTest, ECEFToWGS84)
+    TEST_F(GeoreferencingConversionTest, ECEFToWGS84)
     {
-        using namespace ROS2::WGS;
+        using namespace Georeferencing::WGS;
         const AZStd::vector<AZStd::pair<Vector3d, WGS84Coordinate>> inputGoldSet = {
             { { 5903307.167667380, 2148628.092761247, 1100300.642188661 }, { 10.0, 20.0, 300.0 } },
             { { -2154856.524084172, 379959.3447517005, -5971509.853428957 }, { -70.0, 170.0, 500.0 } },
@@ -90,7 +90,7 @@ namespace UnitTest
         };
         for (const auto& [input, goldResult] : inputGoldSet)
         {
-            const auto result = ROS2::Utils::GeodeticConversions::ECEFToWGS84(input);
+            const auto result = Georeferencing::Utils::GeodeticConversions::ECEFToWGS84(input);
             EXPECT_NEAR(result.m_longitude, goldResult.m_longitude, OneMillimeterInDegreesOnEquator);
             EXPECT_NEAR(result.m_latitude, goldResult.m_latitude, OneMillimeterInDegreesOnEquator);
             EXPECT_NEAR(result.m_altitude, goldResult.m_altitude, OneMillimiter);

+ 12 - 0
Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingTest.cpp

@@ -0,0 +1,12 @@
+/*
+* Copyright (c) Contributors to the Open 3D Engine Project.
+* For complete copyright and license terms please see the LICENSE at the root of this distribution.
+*
+* SPDX-License-Identifier: Apache-2.0 OR MIT
+*
+*/
+
+
+#include <AzTest/AzTest.h>
+
+AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

+ 237 - 0
Gems/LevelGeoreferencing/Code/Tests/Tools/GeoreferenceComponentTest.cpp

@@ -0,0 +1,237 @@
+
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzCore/Asset/AssetManagerComponent.h>
+#include <AzCore/Component/ComponentApplication.h>
+#include <AzCore/Component/ComponentApplicationBus.h>
+#include <AzCore/Component/Entity.h>
+#include <AzCore/Component/EntityId.h>
+#include <AzCore/RTTI/RTTIMacros.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Slice/SliceAssetHandler.h>
+#include <AzCore/UserSettings/UserSettingsComponent.h>
+#include <AzCore/std/containers/array.h>
+#include <AzCore/std/string/string_view.h>
+#include <AzQtComponents/Utilities/QtPluginPaths.h>
+#include <AzTest/GemTestEnvironment.h>
+#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
+#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
+#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
+#include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
+
+#include <QApplication>
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "Clients/GeoreferenceLevelComponent.h"
+#include "Clients/GeoreferencingSystemComponent.h"
+#include <Georeferencing/GeoreferenceBus.h>
+namespace UnitTest
+{
+    constexpr float OneMillimeter = 0.001f;
+    constexpr double MaxWGSError = 0.001 * (1.0 / 60.0 / 60.0); // 0.001 arc second
+    class GeoreferenceComponentTestEnvironment : public AZ::Test::GemTestEnvironment
+    {
+        // AZ::Test::GemTestEnvironment overrides ...
+        void AddGemsAndComponents() override;
+        AZ::ComponentApplication* CreateApplicationInstance() override;
+        void PostSystemEntityActivate() override;
+
+    public:
+        GeoreferenceComponentTestEnvironment() = default;
+        ~GeoreferenceComponentTestEnvironment() override = default;
+    };
+
+    void GeoreferenceComponentTestEnvironment::AddGemsAndComponents()
+    {
+        AddActiveGems(AZStd::to_array<AZStd::string_view>({ "LevelGeoreferencing" }));
+        AddDynamicModulePaths({});
+        AddComponentDescriptors(AZStd::initializer_list<AZ::ComponentDescriptor*>{
+            Georeferencing::GeoReferenceLevelComponent::CreateDescriptor(),
+            Georeferencing::GeoreferencingSystemComponent::CreateDescriptor(),
+        });
+        AddRequiredComponents(AZStd::to_array<AZ::TypeId const>({ Georeferencing::GeoreferencingSystemComponent::TYPEINFO_Uuid() }));
+    }
+
+    AZ::ComponentApplication* GeoreferenceComponentTestEnvironment::CreateApplicationInstance()
+    {
+        // Using ToolsTestApplication to have AzFramework and AzToolsFramework components.
+        return aznew UnitTest::ToolsTestApplication("GeoreferenceComponentTestEnvironment");
+    }
+
+    void GeoreferenceComponentTestEnvironment::PostSystemEntityActivate()
+    {
+        AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
+    }
+
+    class GeoreferenceComponentTestFixture : public ::testing::Test
+    {
+    protected:
+        void SetUp() override;
+        void TearDown() override;
+        AZ::Entity* m_levelEntity;
+        AZ::Entity* m_originEntity;
+    };
+
+    void GeoreferenceComponentTestFixture::SetUp()
+    {
+        m_levelEntity = aznew AZ::Entity();
+        m_originEntity = aznew AZ::Entity();
+
+        AZ_Assert(m_levelEntity, "Failed to create level entity");
+        AZ_Assert(m_originEntity, "Failed to create origin entity");
+
+        auto component = m_levelEntity->CreateComponent<Georeferencing::GeoReferenceLevelComponent>();
+        AZ_Assert(component, "Failed to create GeoreferenceLevelComponent");
+
+        auto transformComponent = m_originEntity->CreateComponent<AzFramework::TransformComponent>();
+        AZ_Assert(transformComponent, "Failed to create TransformComponent");
+
+        m_levelEntity->Init();
+        m_originEntity->Init();
+        m_levelEntity->Activate();
+        m_originEntity->Activate();
+
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginEntity, m_originEntity->GetId());
+    }
+
+    void GeoreferenceComponentTestFixture::TearDown()
+    {
+        delete m_levelEntity;
+        delete m_originEntity;
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, ComponentSmokeTest)
+    {
+        EXPECT_TRUE(m_levelEntity->GetState() == AZ::Entity::State::Active);
+        EXPECT_TRUE(m_originEntity->GetState() == AZ::Entity::State::Active);
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, TestConfiguration)
+    {
+        // Set the origin entity as the origin of the level entity
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginEntity, m_originEntity->GetId());
+
+        // Set origin coordinates
+        Georeferencing::WGS::WGS84Coordinate originCoordinate;
+        originCoordinate.SetAltitude(0.0);
+        originCoordinate.SetLatitude(25.0);
+        originCoordinate.SetAltitude(35.0);
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginCoordinates, originCoordinate);
+
+        AZ::EntityId originEntityId;
+        Georeferencing::GeoreferenceConfigurationRequestsBus::BroadcastResult(
+            originEntityId, &Georeferencing::GeoreferenceConfigurationRequests::GetOriginEntity);
+        EXPECT_TRUE(originEntityId == m_originEntity->GetId());
+
+        Georeferencing::WGS::WGS84Coordinate originCoordinateResult;
+        Georeferencing::GeoreferenceConfigurationRequestsBus::BroadcastResult(
+            originCoordinateResult, &Georeferencing::GeoreferenceConfigurationRequests::GetOriginCoordinates);
+        EXPECT_TRUE(originCoordinateResult == originCoordinate);
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, TestConversionToLevelAtOrigin)
+    {
+        // Set origin coordinates
+        const Georeferencing::WGS::WGS84Coordinate originCoordinate{ 25.0, 35.0, 0.0 };
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginCoordinates, originCoordinate);
+
+        // convert to level
+        AZ::Vector3 levelCoordinate;
+        Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+            levelCoordinate, &Georeferencing::GeoreferenceRequests::ConvertFromWGS84ToLevel, originCoordinate);
+
+        EXPECT_NEAR(levelCoordinate.GetX(), 0.0, OneMillimeter);
+        EXPECT_NEAR(levelCoordinate.GetY(), 0.0, OneMillimeter);
+        EXPECT_NEAR(levelCoordinate.GetZ(), 0.0, OneMillimeter);
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, TestConversionToWGS84AtOrigin)
+    {
+        // Set origin coordinates
+        const Georeferencing::WGS::WGS84Coordinate originCoordinate{ 25.0, 35.0, 0.0 };
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginCoordinates, originCoordinate);
+
+        Georeferencing::WGS::WGS84Coordinate resultCoordinate;
+        Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+            resultCoordinate, &Georeferencing::GeoreferenceRequests::ConvertFromLevelToWGS84, AZ::Vector3::CreateZero());
+
+        EXPECT_NEAR(resultCoordinate.GetLatitude(), 25.0, MaxWGSError);
+        EXPECT_NEAR(resultCoordinate.GetLongitude(), 35.0, MaxWGSError);
+        EXPECT_NEAR(resultCoordinate.GetAltitude(), 0.0, MaxWGSError);
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, TestNavigationInDirectionENU)
+    {
+        // Set origin coordinates
+        const Georeferencing::WGS::WGS84Coordinate originCoordinate{ 25.0, 35.0, 0.0 };
+
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginCoordinates, originCoordinate);
+
+        const AZ::Vector3 north = AZ::Vector3::CreateAxisY(); // One meter north
+
+        Georeferencing::WGS::WGS84Coordinate resultCoordinate;
+        Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+            resultCoordinate, &Georeferencing::GeoreferenceRequests::ConvertFromLevelToWGS84, north);
+
+        EXPECT_GT(resultCoordinate.GetLatitude(), 25.0);
+        EXPECT_NEAR(resultCoordinate.GetLongitude(), 35.0, MaxWGSError);
+        EXPECT_NEAR(resultCoordinate.GetAltitude(), 0.0, MaxWGSError);
+    }
+
+    TEST_F(GeoreferenceComponentTestFixture, TestNavigationInDirectionRotatedENU)
+    {
+        // Set origin coordinates
+        const Georeferencing::WGS::WGS84Coordinate originCoordinate{ 25.0, 35.0, 0.0 };
+
+        Georeferencing::GeoreferenceConfigurationRequestsBus::Broadcast(
+            &Georeferencing::GeoreferenceConfigurationRequests::SetOriginCoordinates, originCoordinate);
+
+        // level is rotated 90 degrees around Z axis
+        // positive X direction is of the level is now pointing east
+        // negative Y direction is of the level is now pointing north
+        const AZ::Transform transform = AZ::Transform::CreateRotationZ(AZ::DegToRad(90.0));
+        AZ_Assert(m_originEntity, "No origin entity");
+        AZ_Assert(m_originEntity->GetState() == AZ::Entity::State::Active, "Origin entity is not active");
+        AZ::TransformBus::Event(m_originEntity->GetId(), &AZ::TransformBus::Events::SetWorldTM, transform);
+
+        // Query is point straight north
+        const Georeferencing::WGS::WGS84Coordinate queryCoordinate{ 25.001, 35.0, 0.0 };
+
+        AZ::Vector3 resultLevel;
+        Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+            resultLevel, &Georeferencing::GeoreferenceRequests::ConvertFromWGS84ToLevel, queryCoordinate);
+        EXPECT_LT(resultLevel.GetX(), 0.0);
+        EXPECT_NEAR(resultLevel.GetY(), 0.0, OneMillimeter);
+    }
+
+} // namespace UnitTest
+
+// required to support running integration tests with Qt and PhysX
+AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv)
+{
+    ::testing::InitGoogleMock(&argc, argv);
+    AzQtComponents::PrepareQtPaths();
+    QApplication app(argc, argv);
+    AZ::Test::printUnusedParametersWarning(argc, argv);
+    AZ::Test::addTestEnvironments({ new UnitTest::GeoreferenceComponentTestEnvironment() });
+    int result = RUN_ALL_TESTS();
+    return result;
+}
+
+IMPLEMENT_TEST_EXECUTABLE_MAIN();

+ 10 - 0
Gems/LevelGeoreferencing/Code/georeferencing_api_files.cmake

@@ -0,0 +1,10 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+        Include/Georeferencing/GeoreferencingTypeIds.h
+        Include/Georeferencing/GeoreferenceBus.h
+        Include/Georeferencing/GeoreferenceStructures.h
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/georeferencing_editor_api_files.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+
+set(FILES
+)

+ 11 - 0
Gems/LevelGeoreferencing/Code/georeferencing_editor_private_files.cmake

@@ -0,0 +1,11 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Source/Tools/GeoreferencingEditorSystemComponent.cpp
+    Source/Tools/GeoreferencingEditorSystemComponent.h
+    Source/Tools/GeoreferenceLevelEditorComponent.cpp
+    Source/Tools/GeoreferenceLevelEditorComponent.h
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/georeferencing_editor_shared_files.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Source/Tools/GeoreferencingEditorModule.cpp
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/georeferencing_editor_tests_files.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Tests/Tools/GeoreferenceComponentTest.cpp
+)

+ 18 - 0
Gems/LevelGeoreferencing/Code/georeferencing_private_files.cmake

@@ -0,0 +1,18 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Source/GeoreferencingModuleInterface.cpp
+    Source/GeoreferencingModuleInterface.h
+    Source/Clients/GeoreferenceInternalStructures.cpp
+    Source/Clients/GeoreferenceInternalStructures.h
+    Source/Clients/GeoreferencingSystemComponent.cpp
+    Source/Clients/GeoreferencingSystemComponent.h
+    Source/Clients/GNSSFormatConversions.cpp
+    Source/Clients/GNSSFormatConversions.h
+    Source/Clients/GeoreferenceStructures.cpp
+    Source/Clients/GeoreferenceLevelComponent.cpp
+    Source/Clients/GeoreferenceLevelComponent.h
+)

+ 8 - 0
Gems/LevelGeoreferencing/Code/georeferencing_shared_files.cmake

@@ -0,0 +1,8 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Source/Clients/GeoreferencingModule.cpp
+)

+ 9 - 0
Gems/LevelGeoreferencing/Code/georeferencing_tests_files.cmake

@@ -0,0 +1,9 @@
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+
+set(FILES
+    Tests/Clients/GeoreferencingTest.cpp
+    Tests/Clients/GeoreferencingConversionTest.cpp
+)

+ 4 - 4
Gems/ProteusRobot/Registry/assetprocessor_settings.setreg → Gems/LevelGeoreferencing/Registry/assetprocessor_settings.setreg

@@ -2,13 +2,13 @@
     "Amazon": {
         "AssetProcessor": {
             "Settings": {
-                "ScanFolder ProteusRobot/Assets": {
-                    "watch": "@GEMROOT:ProteusRobot@/Assets",
+                "ScanFolder LevelGeoreferencing/Assets": {
+                    "watch": "@GEMROOT:LevelGeoreferencing@/Assets",
                     "recursive": 1,
                     "order": 101
                 },
-                "ScanFolder ProteusRobot/Registry": {
-                    "watch": "@GEMROOT:ProteusRobot@/Registry",
+                "ScanFolder LevelGeoreferencing/Registry": {
+                    "watch": "@GEMROOT:LevelGeoreferencing@/Registry",
                     "recursive": 1,
                     "order": 102
                 }

+ 31 - 0
Gems/LevelGeoreferencing/gem.json

@@ -0,0 +1,31 @@
+{
+    "gem_name": "LevelGeoreferencing",
+    "version": "1.0.0",
+    "display_name": "LevelGeoreferencing",
+    "license": "Apache-2.0",
+    "license_url": "https://opensource.org/licenses/Apache-2.0",
+    "origin": "RobotecAI",
+    "origin_url": "https://robotec.ai",
+    "type": "Code",
+    "summary": "Toolset to georeference level",
+    "canonical_tags": [
+        "Gem"
+    ],
+    "user_tags": [
+        "Georeferencing",
+        "LevelGeoreferencing"
+    ],
+    "platforms": [],
+    "icon_path": "preview.png",
+    "requirements": "",
+    "documentation_url": "https://www.docs.o3de.org/docs/user-guide/interactivity/robotics/georeference/",
+    "dependencies": [],
+    "compatible_engines": [
+        "o3de-sdk>=2.4.0",
+        "o3de>=2.4.0"
+    ],
+    "engine_api_dependencies": [],
+    "restricted": "LevelGeoreferencing",
+    "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",
+    "download_source_uri": "https://github.com/o3de/o3de-extras/releases/download/2.0/levelgeoreferencing-1.0.0-gem.zip"
+}

+ 3 - 0
Gems/LevelGeoreferencing/preview.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:248e3ffe1fc9ffc02afb2ba8914e222a5a5d13ac45a48b98c95ee062e959a94c
+size 4475

+ 1 - 1
Gems/MachineLearning/Code/CMakeLists.txt

@@ -102,7 +102,7 @@ ly_add_target(
         PRIVATE
             Gem::${gem_name}.Private.Object
             AZ::AtomCore
-            Gem::Atom_Feature_Common.Static
+            Gem::Atom_Feature_Common.Public
             Gem::ImGui.Static
 )
 

+ 4 - 3
Gems/MachineLearning/gem.json

@@ -1,6 +1,6 @@
 {
     "gem_name": "MachineLearning",
-    "version": "1.0.0",
+    "version": "1.0.1",
     "display_name": "MachineLearning",
     "license": "License used i.e. Apache-2.0 or MIT",
     "license_url": "Link to the license web site i.e. https://opensource.org/licenses/Apache-2.0",
@@ -21,8 +21,9 @@
     "requirements": "Notice of any requirements for this Gem i.e. This requires X other gem",
     "documentation_url": "Link to any documentation of your Gem",
     "dependencies": [],
-    "repo_uri": "",
+    "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",
     "compatible_engines": [],
     "engine_api_dependencies": [],
-    "restricted": "MachineLearning"
+    "restricted": "MachineLearning",
+    "download_source_uri": "https://github.com/o3de/o3de-extras/releases/download/2.0/machinelearning-1.0.1-gem.zip"
 }

+ 2 - 9
Gems/OpenXRVk/3rdParty/Platform/Android/BuiltInPackages_android.cmake

@@ -6,12 +6,5 @@
 #
 #
 
-set(ANDROID_USE_OCULUS_OPENXR OFF CACHE BOOL "When ON it uses OpenXR library from Oculus SDK.")
-
-if(ANDROID_USE_OCULUS_OPENXR)
-    include(${CMAKE_CURRENT_LIST_DIR}/FindOpenXROculus.cmake)
-    set(openxr_dependency 3rdParty::OpenXROculus)
-else()
-    ly_associate_package(PACKAGE_NAME OpenXR-1.0.22-rev1-android    TARGETS OpenXR  PACKAGE_HASH 1227204583ce224c7e3843e82bb36deb576df6b458eecce46740cb8941902f21)
-    set(openxr_dependency 3rdParty::OpenXR)
-endif()
+ly_associate_package(PACKAGE_NAME OpenXR-1.1.41-rev2-android    TARGETS OpenXR  PACKAGE_HASH ffd5b4c4a7f9f1af1bd2f58dfd9907c91ffad92e0eacaaabf1779607ecf673f4)
+set(openxr_dependency 3rdParty::OpenXR)

+ 0 - 42
Gems/OpenXRVk/3rdParty/Platform/Android/FindOpenXROculus.cmake

@@ -1,42 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-# 
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#
-
-# this file actually ingests the library and defines targets.
-set(TARGET_WITH_NAMESPACE "3rdParty::OpenXROculus")
-if (TARGET ${TARGET_WITH_NAMESPACE})
-    return()
-endif()
-
-set(MY_NAME "OpenXROculus")
-
-get_property(openxrvk_gem_root GLOBAL PROPERTY "@GEMROOT:OpenXRVk@")
-
-set(OculusOpenXRSDKPath ${openxrvk_gem_root}/External/OculusOpenXRMobileSDK)
-
-set(${MY_NAME}_INCLUDE_DIR 
-    ${OculusOpenXRSDKPath}/3rdParty/khronos/openxr/OpenXR-SDK/include
-    ${OculusOpenXRSDKPath}/OpenXR/Include)
-
-set(PATH_TO_SHARED_LIBS ${OculusOpenXRSDKPath}/OpenXR/Libs/Android/arm64-v8a)
-
-if(NOT EXISTS ${PATH_TO_SHARED_LIBS}/Release/libopenxr_loader.so)
-    message(FATAL_ERROR
-        "Oculus OpenXR loader library not found at ${PATH_TO_SHARED_LIBS}/Release. "
-        "Oculus OpenXR Mobile SDK needs to be downloaded via https://developer.oculus.com/downloads/native-android/ "
-        "and uncompressed into OpenXRVk/External/OculusOpenXRMobileSDK folder.")
-    return()
-endif()
-
-add_library(${TARGET_WITH_NAMESPACE} SHARED IMPORTED GLOBAL)
-ly_target_include_system_directories(TARGET ${TARGET_WITH_NAMESPACE} INTERFACE ${${MY_NAME}_INCLUDE_DIR})
-set_target_properties(${TARGET_WITH_NAMESPACE}
-    PROPERTIES
-        IMPORTED_LOCATION ${PATH_TO_SHARED_LIBS}/Release/libopenxr_loader.so
-        IMPORTED_LOCATION_DEBUG ${PATH_TO_SHARED_LIBS}/Debug/libopenxr_loader.so)
-
-set(${MY_NAME}_FOUND True)

+ 2 - 2
Gems/OpenXRVk/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake

@@ -6,6 +6,6 @@
 #
 #
 
-ly_associate_package(PACKAGE_NAME OpenXR-1.0.22-rev1-windows    TARGETS OpenXR  PACKAGE_HASH 55235d77253efe1af046a4a3e7dd7a8e5f6768401326d5e077c827cce323cd11)
-
+ly_associate_package(PACKAGE_NAME OpenXR-1.1.41-rev2-windows    TARGETS OpenXR  PACKAGE_HASH 3fabbf5db71fa75d296417861bb7df2bd782d8a7bb7a60c7854cdf768dcdca53)
 set(openxr_dependency 3rdParty::OpenXR)
+

+ 0 - 7
Gems/OpenXRVk/External/OculusOpenXRMobileSDK/README.md

@@ -1,7 +0,0 @@
-# Oculus OpenXR Mobile SDK
-
-The Oculus OpenXR Mobile SDK is not included as part of O3DE.
-
-When enabling OpenXRVk Gem, download the SDK and uncompress it in the following folder within the gem: `OpenXRVk\External\OculusOpenXRMobileSDK`
-
-The Oculus OpenXR Mobile SDK can be found in the following link: https://developer.oculus.com/downloads/native-android/

+ 2 - 2
Gems/OpenXRVk/gem.json

@@ -15,6 +15,6 @@
     "documentation_url": "",
     "dependencies": [],
     "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",
-    "download_source_uri": "https://github.com/o3de/o3de-extras/releases/download/2.0/openxrvk-1.0.1-gem.zip",
-    "version": "1.0.1"
+    "download_source_uri": "https://github.com/o3de/o3de-extras/releases/download/2.0/openxrvk-1.1.0-gem.zip",
+    "version": "1.1.0"
 }

+ 0 - 18
Gems/ProteusRobot/Assets/Materials/Proteus_chassis_Proteus.material

@@ -1,18 +0,0 @@
-{
-    "materialType": "@gemroot:Atom_Feature_Common@/Assets/Materials/Types/StandardPBR.materialtype",
-    "materialTypeVersion": 5,
-    "propertyValues": {
-        "baseColor.textureMap": "../Textures/Proteus_BaseMap.png",
-        "emissive.enable": true,
-        "emissive.intensity": 7.420000076293945,
-        "emissive.textureMap": "../Textures/Lights_Emissive.png",
-        "metallic.textureMap": "../Textures/Proteus_MaskMap_R.png",
-        "normal.textureMap": "../Textures/Proteus_Normal.png",
-        "opacity.factor": 1.0,
-        "roughness.factor": 0.5,
-        "roughness.lowerBound": 0.49000000953674316,
-        "roughness.textureMap": "../Textures/Proteus_MaskMap_A.png",
-        "roughness.upperBound": 0.15000000596046448,
-        "specularF0.factor": 0.5099999904632568
-    }
-}

+ 0 - 13
Gems/ProteusRobot/Assets/Materials/Proteus_chassis_Side_Lights.material

@@ -1,13 +0,0 @@
-{
-    "materialType": "@gemroot:Atom_Feature_Common@/Assets/Materials/Types/StandardPBR.materialtype",
-    "materialTypeVersion": 5,
-    "propertyValues": {
-        "baseColor.textureMap": "../Textures/Lights_Emissive.png",
-        "emissive.enable": true,
-        "emissive.intensity": 7.0,
-        "emissive.textureMap": "../Textures/Lights_Emissive.png",
-        "normal.textureMap": "../Textures/Proteus_Normal.png",
-        "opacity.factor": 1.0,
-        "roughness.factor": 0.5
-    }
-}

+ 0 - 19
Gems/ProteusRobot/Assets/Materials/Proteus_chassis_wheel.material

@@ -1,19 +0,0 @@
-{
-    "materialType": "@gemroot:Atom_Feature_Common@/Assets/Materials/Types/StandardPBR.materialtype",
-    "materialTypeVersion": 5,
-    "propertyValues": {
-        "baseColor.textureBlendMode": "LinearLight",
-        "baseColor.textureMap": "../Textures/Proteus_BaseMap.png",
-        "emissive.enable": true,
-        "emissive.intensity": 7.420000076293945,
-        "emissive.textureMap": "../Textures/Lights_Emissive.png",
-        "metallic.textureMap": "../Textures/Proteus_MaskMap_R.png",
-        "normal.textureMap": "../Textures/Proteus_Normal.png",
-        "opacity.factor": 1.0,
-        "roughness.factor": 0.5,
-        "roughness.lowerBound": 0.20000000298023224,
-        "roughness.textureMap": "../Textures/Proteus_MaskMap_A.png",
-        "roughness.upperBound": 0.9399999976158142,
-        "specularF0.factor": 0.5099999904632568
-    }
-}

+ 0 - 3
Gems/ProteusRobot/Assets/Proteus2_chassis.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a62150544cf58a4527f317a0ea316d046f92fa90d38a61c0b2e99037095c59d0
-size 170876

+ 0 - 3
Gems/ProteusRobot/Assets/Proteus2_lift.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:76809288546fa028f263dbdd20eacfe2730a90895dec38db826d5521ddf1fc3e
-size 79244

+ 0 - 3
Gems/ProteusRobot/Assets/Proteus_chassis.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4586a1c9a8e18c353d534b23222c6b1b1e11b3e842b7ed35f190548251999906
-size 225948

+ 0 - 3
Gems/ProteusRobot/Assets/Proteus_wheel.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6937ad1b662f2688000526b7bf871af33aac1acd99cfe4535b8e2ce70e902983
-size 32124

+ 0 - 3
Gems/ProteusRobot/Assets/Textures/Proteus_MaskMap.png

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ad1935486899cc0664f8d4aa428e626cb452dcfe639494fe420f96ee71ff62c0
-size 2267401

+ 0 - 3
Gems/ProteusRobot/Assets/Textures/Proteus_MaskMap_A.png

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:676539bb24018bd20e5102c6e5d14148ff418758bd4da0c2e281a73f54632993
-size 567314

+ 0 - 30
Gems/ProteusRobot/README.md

@@ -1,30 +0,0 @@
-[![Apache License, Version 2.0][apache_shield]][apache]
-
-# Proteus Robot Gem for Open 3D Engine (O3DE)
-
-## Requirements
-- Any O3DE project with the [ROS 2 Gem](https://docs.o3de.org/docs/user-guide/interactivity/robotics/) enabled.
-
-Please refer to [O3DE documentation](https://docs.o3de.org/docs/user-guide/gems/) to learn more about Gems and about registering Gems in the system and O3DE projects.
-
-## Description
-This is an Asset Gem. It contains a simplified model of [Proteus Robot](https://robotsguide.com/robots/proteus) - an autonomous mobile robot that can pick up, transport, and drop off containers. It is delivered as a ready-to-use O3DE prefab, `Proteus.prefab`, containing visual models, physics and the following ROS 2 components:
-- `ROS2 Frame`
-- `ROS2 Robot Control`
-- `ROS2 Skid Steering Twist Control`
-- `ROS2 Lidar Sensor`
-
-Additionally, the model is equipped with links that are suitable for adding `Camera` and `Imu` sensors.
-
-The robot publishes Lidar Sensor's output on the`/base_link/pc` ROS 2 topic and can be driven using the `/base_link/cmd_vel` ROS 2 topic. An example of its use can be found in [ROS 2 Project Template](https://github.com/o3de/o3de-extras/tree/development/Templates/Ros2FleetRobotTemplate).
-
-## Screenshots
-![](docs/images/front.png)
-![](docs/images/back.png)
-
-## Acknowledgments
-This work is licensed under [Apache License, Version 2.0][apache]. You may elect at your option to use the [MIT License][mit] instead. Contributions must be made under both licenses.
-
-[apache]: https://opensource.org/licenses/Apache-2.0
-[mit]: https://opensource.org/licenses/MIT
-[apache_shield]: https://img.shields.io/badge/License-Apache_2.0-blue.svg

+ 0 - 35
Gems/ProteusRobot/gem.json

@@ -1,35 +0,0 @@
-{
-    "gem_name": "ProteusRobot",
-    "version": "2.0.0",
-    "display_name": "Proteus Robot",
-    "license": "Apache-2.0 or MIT",
-    "license_url": "https://opensource.org/licenses/Apache-2.0",
-    "origin": "RobotecAI",
-    "origin_url": "https://robotec.ai",
-    "type": "Asset",
-    "summary": "Proteus warehouse robot with Lidar sensor",
-    "canonical_tags": [
-        "Gem"
-    ],
-    "user_tags": [
-        "ProteusRobot"
-    ],
-    "platforms": [
-        ""
-    ],
-    "icon_path": "preview.png",
-    "requirements": "Requires ROS 2 Gem",
-    "documentation_url": "https://www.o3de.org/docs/user-guide/interactivity/robotics/project-configuration/#ros-2-project-templates",
-    "dependencies": [
-        "ROS2>=3.1.0"
-    ],
-    "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",
-    "compatible_engines": [
-        "o3de-sdk>=2.3.0",
-        "o3de>=2.3.0"
-    ],
-    "engine_api_dependencies": [],
-    "restricted": "ProteusRobot",
-    "download_source_uri": "https://github.com/o3de/o3de-extras/releases/download/2.0/proteusrobot-2.0.0-gem.zip"
-}
-

+ 0 - 3
Gems/ProteusRobot/preview.png

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4f1c54b47691f37f59463ff5926c44bba4783f526512485704167502d840f76c
-size 19282

+ 0 - 3
Gems/ROS2/Assets/Models/Sensors/Camera/CameraOrbbeck.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a409d15dff6905764f833d9c1776d91d47aa106cea0f36def24d3997e3f670b7
-size 86204

+ 0 - 3
Gems/ROS2/Assets/Models/Sensors/LidarOS2/LidarOS2.fbx

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d1a630c97a3b192f56b42e87650edfb1f10a4967cb2c7211d7ac00eb487d1b0f
-size 237180

+ 0 - 3
Gems/ROS2/Assets/Models/Sensors/LidarOS2/textures/AO_green.png

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f312eb2eac4a1d5cf7f3ebbdccc5f9e7095b810a912f715926c39b7d18864e91
-size 901336

+ 0 - 3
Gems/ROS2/Assets/Models/Sensors/LidarOS2/textures/Smoothness.png

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:702ab6984e68abcfc434e90f3475badc9bbeeb8ef7edadd986ec84db985951a1
-size 123513

+ 0 - 163
Gems/ROS2/Assets/Prefabs/Sensors/CameraOrbbeck.prefab

@@ -1,163 +0,0 @@
-{
-    "ContainerEntity": {
-        "Id": "ContainerEntity",
-        "Name": "CameraOrbbeck",
-        "Components": {
-            "Component_[11102275644839424768]": {
-                "$type": "EditorDisabledCompositionComponent",
-                "Id": 11102275644839424768
-            },
-            "Component_[13196476423961983989]": {
-                "$type": "EditorVisibilityComponent",
-                "Id": 13196476423961983989
-            },
-            "Component_[13762686544738860494]": {
-                "$type": "EditorPendingCompositionComponent",
-                "Id": 13762686544738860494
-            },
-            "Component_[14647808383678281689]": {
-                "$type": "EditorPrefabComponent",
-                "Id": 14647808383678281689
-            },
-            "Component_[16541569782343084053]": {
-                "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
-                "Id": 16541569782343084053,
-                "Parent Entity": ""
-            },
-            "Component_[362243497987326595]": {
-                "$type": "EditorEntitySortComponent",
-                "Id": 362243497987326595,
-                "Child Entity Order": [
-                    "Entity_[505721939488]"
-                ]
-            },
-            "Component_[6195463370225568393]": {
-                "$type": "EditorLockComponent",
-                "Id": 6195463370225568393
-            },
-            "Component_[7051867183047048361]": {
-                "$type": "EditorEntityIconComponent",
-                "Id": 7051867183047048361
-            },
-            "Component_[8693333803190442857]": {
-                "$type": "EditorOnlyEntityComponent",
-                "Id": 8693333803190442857
-            },
-            "Component_[921489768285039708]": {
-                "$type": "EditorInspectorComponent",
-                "Id": 921489768285039708
-            }
-        }
-    },
-    "Entities": {
-        "Entity_[505721939488]": {
-            "Id": "Entity_[505721939488]",
-            "Name": "shape",
-            "Components": {
-                "Component_[12057597801334645923]": {
-                    "$type": "EditorStaticRigidBodyComponent",
-                    "Id": 12057597801334645923
-                },
-                "Component_[12232650884412772636]": {
-                    "$type": "EditorDisabledCompositionComponent",
-                    "Id": 12232650884412772636
-                },
-                "Component_[13423704711553959863]": {
-                    "$type": "EditorLockComponent",
-                    "Id": 13423704711553959863
-                },
-                "Component_[14616296837285217185]": {
-                    "$type": "EditorVisibilityComponent",
-                    "Id": 14616296837285217185
-                },
-                "Component_[14985514809153430690]": {
-                    "$type": "EditorMeshColliderComponent",
-                    "Id": 14985514809153430690,
-                    "ColliderConfiguration": {
-                        "MaterialSlots": {
-                            "Slots": [
-                                {
-                                    "Name": "DefaultMaterial"
-                                }
-                            ]
-                        }
-                    },
-                    "ShapeConfiguration": {
-                        "PhysicsAsset": {
-                            "Asset": {
-                                "assetId": {
-                                    "guid": "{0E27CF27-5752-5557-B77A-4B29A5870E0E}",
-                                    "subId": 3865077323
-                                },
-                                "assetHint": "models/sensors/camera/cameraorbbeck.fbx.pxmesh"
-                            },
-                            "Configuration": {
-                                "PhysicsAsset": {
-                                    "assetId": {
-                                        "guid": "{0E27CF27-5752-5557-B77A-4B29A5870E0E}",
-                                        "subId": 3865077323
-                                    },
-                                    "loadBehavior": "QueueLoad",
-                                    "assetHint": "models/sensors/camera/cameraorbbeck.fbx.pxmesh"
-                                }
-                            }
-                        }
-                    }
-                },
-                "Component_[15329441649387498950]": {
-                    "$type": "AZ::Render::EditorMeshComponent",
-                    "Id": 15329441649387498950,
-                    "Controller": {
-                        "Configuration": {
-                            "ModelAsset": {
-                                "assetId": {
-                                    "guid": "{0E27CF27-5752-5557-B77A-4B29A5870E0E}",
-                                    "subId": 272993556
-                                },
-                                "assetHint": "models/sensors/camera/cameraorbbeck.azmodel"
-                            }
-                        }
-                    }
-                },
-                "Component_[16525421850445080131]": {
-                    "$type": "EditorPendingCompositionComponent",
-                    "Id": 16525421850445080131
-                },
-                "Component_[1664914396196781949]": {
-                    "$type": "EditorEntityIconComponent",
-                    "Id": 1664914396196781949
-                },
-                "Component_[18099860883597356778]": {
-                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
-                    "Id": 18099860883597356778,
-                    "Parent Entity": "ContainerEntity"
-                },
-                "Component_[18322469032445804849]": {
-                    "$type": "EditorOnlyEntityComponent",
-                    "Id": 18322469032445804849
-                },
-                "Component_[2491808840491479985]": {
-                    "$type": "EditorInspectorComponent",
-                    "Id": 2491808840491479985,
-                    "ComponentOrderEntryArray": [
-                        {
-                            "ComponentId": 18099860883597356778
-                        },
-                        {
-                            "ComponentId": 15329441649387498950,
-                            "SortIndex": 1
-                        },
-                        {
-                            "ComponentId": 14985514809153430690,
-                            "SortIndex": 2
-                        }
-                    ]
-                },
-                "Component_[6578496273892635118]": {
-                    "$type": "EditorEntitySortComponent",
-                    "Id": 6578496273892635118
-                }
-            }
-        }
-    }
-}

+ 29 - 4
Gems/ROS2/Code/CMakeLists.txt

@@ -42,6 +42,25 @@ add_custom_target(
     COMMAND ${CMAKE_COMMAND} -DROS_DISTRO=${ROS_DISTRO} -P ${CMAKE_CURRENT_SOURCE_DIR}/checkROS2Distribution.cmake
 )
 
+# Gazebo messages are optional, so we will only add the dependents if the package is found.
+# The gazebo_msgs package is EOL and will not be available in ROS 2 Kilted Kaiju.
+# If you need to use ContactSensor and/or ROS2 Spawner, please consider building gazebo_msgs from the source.
+find_package(gazebo_msgs QUIET)
+if (gazebo_msgs_FOUND)
+    message(STATUS "Found gazebo_msgs package, enabling legacy features like ContactSensor Component and ROS2 Spawner Component")
+    SET (WITH_GAZEBO_MSGS TRUE)
+    if(NOT (ROS_DISTRO STREQUAL "humble" OR ROS_DISTRO STREQUAL "jazzy"))
+        message(WARNING
+                "The support for deprecated gazebo_msgs package is not supported in ROS 2 Kilted or newer. "
+                "Please consider migration to Simulation Interfaces. "
+                "If you do not intend to use Gazebo messages, please make sure that this package is not sourced in your environment." )
+
+    endif()
+else()
+    message(STATUS "Could not find gazebo_msgs package, disabling legacy features like ContactSensor Component and ROS2 Spawner Component")
+    SET(WITH_GAZEBO_MSGS FALSE)
+endif()
+
 # Add the ROS2.Static target
 # Note: We include the common files and the platform specific files which are set in ros2_common_files.cmake
 # and in ${pal_dir}/ros2_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
@@ -62,15 +81,21 @@ ly_add_target(
             AZ::AzCore
             AZ::AzFramework
             Gem::Atom_RPI.Public
-            Gem::Atom_Feature_Common.Static
+            Gem::Atom_Feature_Common.Public
             Gem::Atom_Component_DebugCamera.Static
             Gem::Atom_AtomBridge.Static
             Gem::StartingPointInput
             Gem::PhysX5.Static
             Gem::LmbrCentral.API
+            Gem::LevelGeoreferencing.API
 )
 
-target_depends_on_ros2_packages(${gem_name}.Static rclcpp builtin_interfaces std_msgs sensor_msgs nav_msgs tf2_ros ackermann_msgs gazebo_msgs control_msgs)
+target_depends_on_ros2_packages(${gem_name}.Static rclcpp builtin_interfaces std_msgs sensor_msgs nav_msgs tf2_ros ackermann_msgs vision_msgs control_msgs)
+
+if (WITH_GAZEBO_MSGS)
+    target_depends_on_ros2_package(${gem_name}.Static gazebo_msgs REQUIRED)
+    target_compile_definitions(${gem_name}.Static PUBLIC "WITH_GAZEBO_MSGS")
+endif()
 
 ly_add_target(
     NAME ${gem_name}.API HEADERONLY
@@ -96,7 +121,7 @@ ly_add_target(
     BUILD_DEPENDENCIES
         PRIVATE
             Gem::${gem_name}.Static
-            Gem::Atom_Feature_Common.Static
+            Gem::Atom_Feature_Common.Public
 )
 
 # By default, we will specify that the above target ROS2 would be used by
@@ -157,7 +182,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
         BUILD_DEPENDENCIES
             PUBLIC
                 Gem::${gem_name}.Editor.Static
-                Gem::Atom_Feature_Common.Static
+                Gem::Atom_Feature_Common.Public
     )
 
     # By default, we will specify that the above target ROS2 would be used by

+ 7 - 0
Gems/ROS2/Code/Include/ROS2/Clock/ITimeSource.h

@@ -8,6 +8,8 @@
 #pragma once
 
 #include <builtin_interfaces/msg/time.hpp>
+#include <AzCore/Outcome/Outcome.h>
+#include <AzCore/std/string/string.h>
 
 namespace ROS2
 {
@@ -19,6 +21,11 @@ namespace ROS2
 
         virtual ~ITimeSource() = default;
 
+        //! Sets the time source to the given time.
+        //! @param time The time to set the time source to.
+        //! @return An outcome indicating success or failure.
+        virtual AZ::Outcome<void, AZStd::string> AdjustTime(const builtin_interfaces::msg::Time & time) = 0;
+
         //! Get time as ROS 2 message.
         //! @see ROS2Requests::GetROSTimestamp() for more details.
         virtual builtin_interfaces::msg::Time GetROSTimestamp() const = 0;

+ 7 - 2
Gems/ROS2/Code/Include/ROS2/Clock/ROS2Clock.h

@@ -8,8 +8,10 @@
 #pragma once
 
 #include "ITimeSource.h"
+#include <AzCore/Outcome/Outcome.h>
 #include <AzCore/std/chrono/chrono.h>
 #include <AzCore/std/smart_ptr/unique_ptr.h>
+#include <AzCore/std/string/string.h>
 #include <rclcpp/publisher.hpp>
 #include <rosgraph_msgs/msg/clock.hpp>
 
@@ -21,8 +23,6 @@ namespace ROS2
     //! the /use_sim_time parameter set to true.
     class ROS2Clock
     {
-        static constexpr size_t FramesNumberForStats = 60;
-
     public:
         ROS2Clock();
         ROS2Clock(AZStd::unique_ptr<ITimeSource> timeSource, bool publishClock);
@@ -33,6 +33,11 @@ namespace ROS2
 
         builtin_interfaces::msg::Time GetROSTimestamp() const;
 
+        //! Sets the time source to the given time.
+        //! @param time The time to set the time source to.
+        //! @return An outcome indicating success or failure.
+        AZ::Outcome<void, AZStd::string> AdjustTime(const builtin_interfaces::msg::Time& time) const;
+
         //! Update time in the ROS 2 ecosystem.
         //! This will publish current time to the ROS 2 `/clock` topic, if Clock is configured to do it.
         void Tick();

+ 6 - 0
Gems/ROS2/Code/Include/ROS2/Clock/ROS2TimeSource.h

@@ -25,6 +25,12 @@ namespace ROS2
         //! Get ROS 2 time as ROS2 message.
         //! @see ROS2Requests::GetROSTimestamp() for more details.
         virtual builtin_interfaces::msg::Time GetROSTimestamp() const override;
+
+        //! Sets the time source to the given time.
+        //! @param time The time to set the time source to.
+        //! @return An outcome indicating success or failure.
+        virtual AZ::Outcome<void, AZStd::string> AdjustTime(const builtin_interfaces::msg::Time& time) override;
+
     };
 
 } // namespace ROS2

+ 8 - 3
Gems/ROS2/Code/Include/ROS2/Clock/RealTimeSource.h

@@ -14,7 +14,7 @@ namespace ROS2
     //! The RealTimeSource starts from 0 at the start of the simulation.
     //! This time source could be affected by the jitter in the data, simulation
     //! computations or other similar events. On the other hand RealTimeSource
-    //! can remain consistent with the other independent clocks if it is synchronised
+    //! can remain consistent with the other independent clocks if it is synchronized
     //! (e.g. through NTP).
     class RealTimeSource : public ITimeSource
     {
@@ -22,8 +22,13 @@ namespace ROS2
         virtual ~RealTimeSource() = default;
 
         // ITimeSource overrides ...
-        virtual void Activate() override {};
-        virtual void Deactivate() override {};
+        virtual void Activate() override{};
+        virtual void Deactivate() override{};
+
+        //! Sets the time source to the given time.
+        //! @param time The time to set the time source to.
+        //! @return An outcome indicating success or failure.
+        virtual AZ::Outcome<void, AZStd::string> AdjustTime(const builtin_interfaces::msg::Time& time) override;
 
         //! Get simulation time as ROS 2 message.
         //! @see ROS2Requests::GetROSTimestamp() for more details.

+ 6 - 0
Gems/ROS2/Code/Include/ROS2/Clock/SimulationTimeSource.h

@@ -30,12 +30,18 @@ namespace ROS2
         virtual void Activate() override;
         virtual void Deactivate() override;
 
+        //! Sets the time source to the given time.
+        //! @param time The time to set the time source to.
+        //! @return An outcome indicating success or failure.
+        virtual AZ::Outcome<void, AZStd::string> AdjustTime(const builtin_interfaces::msg::Time& time) override;
+
         //! Get ROS 2 time as ROS2 message.
         //! @see ROS2Requests::GetROSTimestamp() for more details.
         virtual builtin_interfaces::msg::Time GetROSTimestamp() const override;
 
     private:
         double m_elapsed = 0;
+        bool m_resetTimeOnRestart = true;
         AzPhysics::SceneEvents::OnSceneSimulationFinishHandler m_onSceneSimulationEvent;
         AzPhysics::SystemEvents::OnSceneAddedEvent::Handler m_onSceneAdded;
         AzPhysics::SystemEvents::OnSceneRemovedEvent::Handler m_onSceneRemoved;

+ 4 - 0
Gems/ROS2/Code/Include/ROS2/Frame/ROS2FrameEditorComponent.h

@@ -74,6 +74,10 @@ namespace ROS2
         AZ::EntityId GetFrameParent() const override;
         AZStd::set<AZ::EntityId> GetFrameChildren() const override;
 
+
+        //! Get the configuration of this component.
+        ROS2FrameConfiguration GetConfiguration() const;
+
     private:
         AZ::Crc32 OnFrameConfigurationChange();
 

+ 0 - 51
Gems/ROS2/Code/Include/ROS2/Georeference/GeoreferenceStructures.h

@@ -1,51 +0,0 @@
-/*
-* Copyright (c) Contributors to the Open 3D Engine Project.
-* For complete copyright and license terms please see the LICENSE at the root of this distribution.
-*
-* SPDX-License-Identifier: Apache-2.0 OR MIT
-*
-*/
-#pragma once
-
-#include <AzCore/RTTI/RTTI.h>
-#include <AzCore/Math/Vector3.h>
-
-namespace ROS2::WGS
-{
-
-    //! WGS84Coordinate is a 3D vector with double precision.
-    //! It is used to represent coordinates in WGS84 coordinate system.
-    struct WGS84Coordinate
-    {
-        AZ_RTTI(WGS84Coordinate, "{577a5637-b31a-44c5-a33f-50df2922af2a}");
-        static void Reflect(AZ::ReflectContext* context);
-
-        WGS84Coordinate();
-        virtual ~WGS84Coordinate() = default;
-
-        WGS84Coordinate(double latitude, double longitude, double altitude);
-        explicit WGS84Coordinate(const AZ::Vector3& latLonAlt);
-
-        [[nodiscard]] AZ::Vector3 ToVector3f() const;
-
-        double m_latitude = 0.0; //!< Latitude in degrees.
-        double m_longitude = 0.0; //!< Longitude in degrees.
-        double m_altitude = 0.0; //!< Altitude in meters.
-    };
-
-    //! Vector3d is a 3D vector with double precision.
-    //! It is used to represent coordinates in ECEF or ENU coordinate systems.
-    struct Vector3d{
-        Vector3d() = default;
-        Vector3d(double x, double y, double z);
-        explicit Vector3d(const AZ::Vector3& xyz);
-        [[nodiscard]] AZ::Vector3 ToVector3f() const;
-
-        Vector3d operator+(Vector3d const& v) const;
-        Vector3d operator-(Vector3d const& v) const;
-
-        double m_x = 0.0; //!< X coordinate in meters.
-        double m_y = 0.0; //! Y coordinate in meters.
-        double m_z = 0.0; //! Z coordinate in meters.
-    };
-}

+ 60 - 0
Gems/ROS2/Code/Include/ROS2/Lidar/ClassSegmentationBus.h

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/Component/EntityId.h>
+#include <AzCore/EBus/EBus.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/Math/Color.h>
+#include <LmbrCentral/Scripting/TagComponentBus.h>
+#include <ROS2/Lidar/SegmentationClassConfiguration.h>
+
+namespace ROS2
+{
+    static constexpr uint8_t UnknownClassId = 0U;
+    static constexpr uint8_t TerrainClassId = 1U;
+    using SegmentationClassConfigList = AZStd::vector<SegmentationClassConfiguration>;
+
+    //! Interface class that allows for retrieval of segmentation class information.
+    class ClassSegmentationRequests
+    {
+    public:
+        AZ_RTTI(ClassSegmentationRequests, "{69b4109e-25ff-482f-b92e-f19cdf06bce2}");
+
+        //! Returns the color of segmentation class with the provided class ID.
+        //! If no segmentation class is found with provided class ID, returns AZ::Colors::White.
+        //! @param classId Class ID of the segmentation class.
+        //! @return Color of the class with provided ID.
+        virtual AZ::Color GetClassColor(uint8_t classId) const = 0;
+
+        //! If segmentation class exists that is associated with provided tag,
+        //! returns ID of this class. Otherwise, returns AZStd::nullopt;
+        //! @param tag Tag associated with the segmentation class.
+        //! @return ID of found class or AZStd::nullopt.
+        virtual AZStd::optional<uint8_t> GetClassIdForTag(LmbrCentral::Tag tag) const = 0;
+
+        //! Returns a reference to the segmentation config list.
+        virtual const SegmentationClassConfigList& GetClassConfigList() const = 0;
+
+    protected:
+        virtual ~ClassSegmentationRequests() = default;
+    };
+
+    class ClassSegmentationRequestBusTraits : public AZ::EBusTraits
+    {
+    public:
+        //////////////////////////////////////////////////////////////////////////
+        // EBusTraits overrides
+        static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+        //////////////////////////////////////////////////////////////////////////
+    };
+
+    using ClassSegmentationRequestBus = AZ::EBus<ClassSegmentationRequests, ClassSegmentationRequestBusTraits>;
+    using ClassSegmentationInterface = AZ::Interface<ClassSegmentationRequests>;
+} // namespace ROS2

+ 14 - 29
Gems/ROS2/Code/Include/ROS2/Lidar/LidarRaycasterBus.h

@@ -11,7 +11,9 @@
 #include <AzCore/EBus/EBus.h>
 #include <AzCore/Math/Transform.h>
 #include <AzCore/Math/Vector3.h>
+#include <AzCore/Outcome/Outcome.h>
 #include <ROS2/Communication/QoS.h>
+#include <ROS2/Lidar/RaycastResults.h>
 
 namespace ROS2
 {
@@ -84,19 +86,12 @@ namespace ROS2
     //! Unique id used by lidar raycasters.
     using LidarId = StronglyTypedUuid<struct LidarIdTag>;
 
-    enum class RaycastResultFlags : AZ::u8
+    //! Structure used to describe both minimal and maximal
+    //! ray travel distance in meters.
+    struct RayRange
     {
-        Points = (1 << 0), //!< return 3D point coordinates
-        Ranges = (1 << 1), //!< return array of distances
-    };
-
-    //! Bitwise operators for RaycastResultFlags
-    AZ_DEFINE_ENUM_BITWISE_OPERATORS(RaycastResultFlags)
-
-    struct RaycastResult
-    {
-        AZStd::vector<AZ::Vector3> m_points;
-        AZStd::vector<float> m_ranges;
+        float m_min{ 0.0f };
+        float m_max{ 0.0f };
     };
 
     //! Interface class that allows for communication with a single Lidar instance.
@@ -110,16 +105,9 @@ namespace ROS2
         //! vector in the positive z direction first by the y, next by the z axis. The x axis is currently not included in calculations.
         virtual void ConfigureRayOrientations(const AZStd::vector<AZ::Vector3>& orientations) = 0;
 
-        //! Configures ray maximum travel distance.
-        //! @param range Ray range in meters.
-        virtual void ConfigureRayRange(float range) = 0;
-
-        //! Configures ray minimum travel distance.
-        //! @param range Ray range in meters.
-        virtual void ConfigureMinimumRayRange(float range)
-        {
-            AZ_Assert(false, "This Lidar Implementation does not support minimum ray range configurations!");
-        }
+        //! Configures ray range.
+        //! @param range Ray range.
+        virtual void ConfigureRayRange(RayRange range) = 0;
 
         //! Configures result flags.
         //! @param flags Raycast result flags define set of data types returned by lidar.
@@ -131,8 +119,10 @@ namespace ROS2
         //! Schedules a raycast that originates from the point described by the lidarTransform.
         //! @param lidarTransform Current transform from global to lidar reference frame.
         //! @param flags Used to request different kinds of data returned by raycast query
-        //! @return Results of the raycast in the requested form including 3D space coordinates and/or ranges.
-        virtual RaycastResult PerformRaycast(const AZ::Transform& lidarTransform) = 0;
+        //! @return Results of the raycast in the requested form if the raycast was successfull or an error message if it was not.
+        //! The returned error messages are c-style string literals which are statically allocated and therefore do not need to be
+        //! dealocated.
+        virtual AZ::Outcome<RaycastResults, const char*> PerformRaycast(const AZ::Transform& lidarTransform) = 0;
 
         //! Configures ray Gaussian Noise parameters.
         //! Each call overrides the previous configuration.
@@ -210,11 +200,6 @@ namespace ROS2
     protected:
         ~LidarRaycasterRequests() = default;
 
-        static void ValidateRayRange([[maybe_unused]] float range)
-        {
-            AZ_Assert(range > 0.0f, "Provided ray range was of incorrect value: Ray range value must be greater than zero.")
-        }
-
         static void ValidateRayOrientations([[maybe_unused]] const AZStd::vector<AZ::Vector3>& orientations)
         {
             AZ_Assert(!orientations.empty(), "Provided ray orientations were of incorrect value: Ray orientations must not be empty.")

+ 11 - 7
Gems/ROS2/Code/Include/ROS2/Lidar/LidarRegistrarBus.h

@@ -16,13 +16,17 @@ namespace ROS2
     //! Enum bitwise flags used to describe LidarSystem's feature support.
     enum LidarSystemFeatures : uint16_t
     {
-        None                    = 0,
-        Noise                   = 1,
-        CollisionLayers         = 1 << 1,
-        EntityExclusion         = 1 << 2,
-        MaxRangePoints          = 1 << 3,
-        PointcloudPublishing    = 1 << 4,
-        All                     = 0b1111111111111111,
+        // clang-format off
+        None =                  0,
+        Noise =                 1,
+        CollisionLayers =       1 << 1,
+        EntityExclusion =       1 << 2,
+        MaxRangePoints =        1 << 3,
+        PointcloudPublishing =  1 << 4,
+        Intensity =             1 << 5,
+        Segmentation =          1 << 6,
+        All =                   (1 << 7) - 1, // All feature bits enabled.
+        // clang-format on
     };
 
     //! Structure used to hold LidarSystem's metadata.

+ 229 - 0
Gems/ROS2/Code/Include/ROS2/Lidar/RaycastResults.h

@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/Math/Vector3.h>
+#include <AzCore/std/containers/span.h>
+#include <AzCore/std/containers/vector.h>
+
+namespace ROS2
+{
+    enum class RaycastResultFlags : AZ::u8
+    {
+        Point = (1 << 0), //!< return 3D point coordinates
+        Range = (1 << 1), //!< return array of distances
+        Intensity = (1 << 2), //!< return intensity data
+        SegmentationData = (1 << 3), //!< return segmentation data
+    };
+
+    //! Bitwise operators for RaycastResultFlags
+    AZ_DEFINE_ENUM_BITWISE_OPERATORS(RaycastResultFlags)
+
+    inline bool IsFlagEnabled(RaycastResultFlags flag, RaycastResultFlags flags)
+    {
+        return (flags & flag) == flag;
+    }
+
+    template<RaycastResultFlags F>
+    struct ResultTraits;
+
+    template<>
+    struct ResultTraits<RaycastResultFlags::Point>
+    {
+        using Type = AZ::Vector3;
+    };
+
+    template<>
+    struct ResultTraits<RaycastResultFlags::Range>
+    {
+        using Type = float;
+    };
+
+    template<>
+    struct ResultTraits<RaycastResultFlags::Intensity>
+    {
+        using Type = float;
+    };
+
+    struct SegmentationIds
+    {
+        int32_t m_entityId;
+        AZ::u8 m_classId;
+    };
+
+    template<>
+    struct ResultTraits<RaycastResultFlags::SegmentationData>
+    {
+        using Type = SegmentationIds;
+    };
+
+    //! Class used for storing the results of a raycast.
+    //! It guarantees a uniform length of all its fields.
+    class RaycastResults
+    {
+    public:
+        template<RaycastResultFlags F, typename RT = typename ResultTraits<F>::Type>
+        using FieldSpan = AZStd::span<RT>;
+
+        template<RaycastResultFlags F>
+        using ConstFieldSpan = FieldSpan<F, const typename ResultTraits<F>::Type>;
+
+        explicit RaycastResults(RaycastResultFlags flags, size_t count = 0U);
+        RaycastResults(const RaycastResults& other) = default;
+        RaycastResults(RaycastResults&& other);
+
+        [[nodiscard]] bool IsEmpty() const;
+
+        template<RaycastResultFlags F>
+        [[nodiscard]] bool IsFieldPresent() const;
+
+        [[nodiscard]] size_t GetCount() const;
+
+        template<RaycastResultFlags F>
+        AZStd::optional<ConstFieldSpan<F>> GetConstFieldSpan() const;
+
+        template<RaycastResultFlags F>
+        AZStd::optional<FieldSpan<F>> GetFieldSpan();
+
+        void Clear();
+        void Resize(size_t count);
+
+        RaycastResults& operator=(const RaycastResults& other) = default;
+        RaycastResults& operator=(RaycastResults&& other);
+
+    private:
+        template<RaycastResultFlags F, typename RT = typename ResultTraits<F>::Type>
+        using FieldInternal = AZStd::optional<AZStd::vector<RT>>;
+
+        template<RaycastResultFlags F>
+        const FieldInternal<F>& GetField() const;
+
+        template<RaycastResultFlags F>
+        FieldInternal<F>& GetField();
+
+        template<RaycastResultFlags F>
+        void ResizeFieldIfPresent(size_t count);
+
+        template<RaycastResultFlags F>
+        void EnsureFlagSatisfied(RaycastResultFlags flags, size_t count);
+
+        template<RaycastResultFlags F>
+        void ClearFieldIfPresent();
+
+        size_t m_count{};
+        FieldInternal<RaycastResultFlags::Point> m_points;
+        FieldInternal<RaycastResultFlags::Range> m_ranges;
+        FieldInternal<RaycastResultFlags::Intensity> m_intensities;
+        FieldInternal<RaycastResultFlags::SegmentationData> m_segmentationData;
+    };
+
+    template<RaycastResultFlags F>
+    bool RaycastResults::IsFieldPresent() const
+    {
+        return GetField<F>().has_value();
+    }
+
+    template<RaycastResultFlags F>
+    AZStd::optional<RaycastResults::ConstFieldSpan<F>> RaycastResults::GetConstFieldSpan() const
+    {
+        auto& field = GetField<F>();
+        if (!field.has_value())
+        {
+            return {};
+        }
+
+        return AZStd::span(field->begin(), field->size());
+    }
+
+    template<RaycastResultFlags F>
+    AZStd::optional<RaycastResults::FieldSpan<F>> RaycastResults::GetFieldSpan()
+    {
+        auto& field = GetField<F>();
+        if (!field.has_value())
+        {
+            return {};
+        }
+
+        return AZStd::span(field->begin(), field->size());
+    }
+
+    template<>
+    inline const RaycastResults::FieldInternal<RaycastResultFlags::Point>& RaycastResults::GetField<RaycastResultFlags::Point>() const
+    {
+        return m_points;
+    }
+
+    template<>
+    inline const RaycastResults::FieldInternal<RaycastResultFlags::Range>& RaycastResults::GetField<RaycastResultFlags::Range>() const
+    {
+        return m_ranges;
+    }
+
+    template<>
+    inline const RaycastResults::FieldInternal<RaycastResultFlags::Intensity>& RaycastResults::GetField<RaycastResultFlags::Intensity>()
+        const
+    {
+        return m_intensities;
+    }
+
+    template<>
+    inline const RaycastResults::FieldInternal<RaycastResultFlags::SegmentationData>& RaycastResults::GetField<
+        RaycastResultFlags::SegmentationData>() const
+    {
+        return m_segmentationData;
+    }
+
+    template<RaycastResultFlags F>
+    RaycastResults::FieldInternal<F>& RaycastResults::GetField()
+    {
+        return const_cast<FieldInternal<F>&>(static_cast<const RaycastResults*>(this)->GetField<F>());
+    }
+
+    template<RaycastResultFlags F>
+    void RaycastResults::ClearFieldIfPresent()
+    {
+        auto& field = GetField<F>();
+        if (!field.has_value())
+        {
+            return;
+        }
+
+        field->clear();
+    }
+
+    template<RaycastResultFlags F>
+    void RaycastResults::ResizeFieldIfPresent(size_t count)
+    {
+        auto& field = GetField<F>();
+        if (!field.has_value())
+        {
+            return;
+        }
+
+        field->resize(count);
+    }
+
+    template<RaycastResultFlags F>
+    void RaycastResults::EnsureFlagSatisfied(RaycastResultFlags flags, size_t count)
+    {
+        if (!IsFlagEnabled(F, flags))
+        {
+            return;
+        }
+
+        auto& field = GetField<F>();
+        if (!field.has_value())
+        {
+            field = AZStd::vector<typename ResultTraits<F>::Type>(count);
+        }
+        else
+        {
+            field->resize(count);
+        }
+    }
+} // namespace ROS2

+ 40 - 0
Gems/ROS2/Code/Include/ROS2/Lidar/SegmentationClassConfiguration.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/Component/EntityId.h>
+#include <AzCore/RTTI/RTTI.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/std/string/string.h>
+
+namespace ROS2
+{
+    //! A structure capturing configuration of a segmentation class.
+    class SegmentationClassConfiguration
+    {
+    public:
+        AZ_TYPE_INFO(SegmentationClassConfiguration, "{e46e75f4-1e0e-48ca-a22f-43afc8f25133}");
+        static void Reflect(AZ::ReflectContext* context);
+
+        static const SegmentationClassConfiguration UnknownClass;
+        static const SegmentationClassConfiguration GroundClass;
+
+        SegmentationClassConfiguration() = default;
+
+        SegmentationClassConfiguration(const AZStd::string& className, const uint8_t classId, const AZ::Color& classColor)
+            : m_className(className)
+            , m_classId(classId)
+            , m_classColor(classColor)
+        {
+        }
+
+        AZStd::string m_className = "Default";
+        uint8_t m_classId = 0;
+        AZ::Color m_classColor = AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
+    };
+} // namespace ROS2

+ 22 - 0
Gems/ROS2/Code/Include/ROS2/Lidar/SegmentationUtils.h

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/Component/EntityId.h>
+
+namespace ROS2::SegmentationUtils
+{
+    //! Returns the segmentation class ID of the entity with provided ID.
+    //! Entity's class ID is fetched using the Tag component (@see Tag).
+    //! If this entity has a tag with a name that matches an existing
+    //! segmentation class (configured through the Class Segmentation component),
+    //! the ID of this class is returned. Otherwise, the Unknown Class ID is returned.
+    //! @param entityId ID of the entity for which a class ID is to be fetched.
+    //! @return Class ID of the entity.
+    [[nodiscard]] uint8_t FetchClassIdForEntity(AZ::EntityId entityId);
+} // namespace ROS2::SegmentationUtils

+ 3 - 0
Gems/ROS2/Code/Include/ROS2/ROS2Bus.h

@@ -64,6 +64,9 @@ namespace ROS2
         //! Obtains a simulation clock that is used across simulation.
         //! @returns constant reference to currently running clock.
         virtual const ROS2Clock& GetSimulationClock() const = 0;
+
+        //! Returns an expected loop time of simulation. It is an estimation from past frames.
+        virtual float GetExpectedSimulationLoopTime() const = 0;
     };
 
     class ROS2BusTraits : public AZ::EBusTraits

Деякі файли не було показано, через те що забагато файлів було змінено