2
0
Эх сурвалжийг харах

Georeferencing gem extracted from ROS 2 (#827)

* Moved Georeferencing code from ROS2 Gem to the new Georeferencing Gem.

Added:
- BehaviourContext
- GeoreferencingTypeIds
- Components tests
- Minor fixes (e.g. comparison operator, copyright headers,
  Transform Bus usage in LevelGeoreferencing)

---------

Signed-off-by: Michał Pełka <[email protected]>
Michał Pełka 5 сар өмнө
parent
commit
c493786731
72 өөрчлөгдсөн 1687 нэмэгдсэн , 198 устгасан
  1. 61 0
      Gems/LevelGeoreferencing/.clang-format
  2. 10 0
      Gems/LevelGeoreferencing/CMakeLists.txt
  3. 257 0
      Gems/LevelGeoreferencing/Code/CMakeLists.txt
  4. 36 4
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceBus.h
  5. 97 0
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferenceStructures.h
  6. 31 0
      Gems/LevelGeoreferencing/Code/Include/Georeferencing/GeoreferencingTypeIds.h
  7. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Android/PAL_android.cmake
  8. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_api_files.cmake
  9. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_private_files.cmake
  10. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Android/georeferencing_shared_files.cmake
  11. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/PAL_linux.cmake
  12. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_api_files.cmake
  13. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_editor_api_files.cmake
  14. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_private_files.cmake
  15. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Linux/georeferencing_shared_files.cmake
  16. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/PAL_mac.cmake
  17. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_api_files.cmake
  18. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_editor_api_files.cmake
  19. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_private_files.cmake
  20. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Mac/georeferencing_shared_files.cmake
  21. 8 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/PAL_windows.cmake
  22. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_api_files.cmake
  23. 7 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_editor_api_files.cmake
  24. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_private_files.cmake
  25. 12 0
      Gems/LevelGeoreferencing/Code/Platform/Windows/georeferencing_shared_files.cmake
  26. 8 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/PAL_ios.cmake
  27. 7 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_api_files.cmake
  28. 12 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_private_files.cmake
  29. 12 0
      Gems/LevelGeoreferencing/Code/Platform/iOS/georeferencing_shared_files.cmake
  30. 3 3
      Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.cpp
  31. 4 3
      Gems/LevelGeoreferencing/Code/Source/Clients/GNSSFormatConversions.h
  32. 50 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.cpp
  33. 29 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceInternalStructures.h
  34. 68 9
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.cpp
  35. 20 5
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceLevelComponent.h
  36. 19 67
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferenceStructures.cpp
  37. 26 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingModule.cpp
  38. 58 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.cpp
  39. 38 0
      Gems/LevelGeoreferencing/Code/Source/Clients/GeoreferencingSystemComponent.h
  40. 42 0
      Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.cpp
  41. 30 0
      Gems/LevelGeoreferencing/Code/Source/GeoreferencingModuleInterface.h
  42. 4 3
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.cpp
  43. 12 14
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferenceLevelEditorComponent.h
  44. 52 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorModule.cpp
  45. 64 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.cpp
  46. 42 0
      Gems/LevelGeoreferencing/Code/Source/Tools/GeoreferencingEditorSystemComponent.h
  47. 14 14
      Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingConversionTest.cpp
  48. 12 0
      Gems/LevelGeoreferencing/Code/Tests/Clients/GeoreferencingTest.cpp
  49. 238 0
      Gems/LevelGeoreferencing/Code/Tests/Tools/GeoreferenceComponentTest.cpp
  50. 11 0
      Gems/LevelGeoreferencing/Code/Tests/Tools/GeoreferencingEditorTest.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. 18 0
      Gems/LevelGeoreferencing/Registry/assetprocessor_settings.setreg
  60. 28 0
      Gems/LevelGeoreferencing/gem.json
  61. 3 0
      Gems/LevelGeoreferencing/preview.png
  62. 1 0
      Gems/ROS2/Code/CMakeLists.txt
  63. 0 51
      Gems/ROS2/Code/Include/ROS2/Georeference/GeoreferenceStructures.h
  64. 4 3
      Gems/ROS2/Code/Source/GNSS/ROS2GNSSSensorComponent.cpp
  65. 0 2
      Gems/ROS2/Code/Source/ROS2EditorModule.cpp
  66. 0 2
      Gems/ROS2/Code/Source/ROS2ModuleInterface.h
  67. 7 6
      Gems/ROS2/Code/Source/Spawner/ROS2SpawnerComponent.cpp
  68. 0 2
      Gems/ROS2/Code/ros2_editor_files.cmake
  69. 0 5
      Gems/ROS2/Code/ros2_files.cmake
  70. 0 3
      Gems/ROS2/Code/ros2_header_files.cmake
  71. 0 1
      Gems/ROS2/Code/ros2_tests_files.cmake
  72. 2 1
      Gems/ROS2/gem.json

+ 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("Georeferencing")
+
+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/Georeferencing/Code/Platform/<platorm_name>  or
+#            <restricted_folder>/<platform_name>/Gems/Georeferencing/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_GEOREFERENCING_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_GEOREFERENCING_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_GEOREFERENCING_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_GEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_GEOREFERENCING_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_GEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_TEST_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_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_GEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_GEOREFERENCING_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_GEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_TEST_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_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_GEOREFERENCING_SUPPORTED TRUE)
+set(PAL_TRAIT_GEOREFERENCING_TEST_SUPPORTED FALSE)
+set(PAL_TRAIT_GEOREFERENCING_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.
+    };
+}

+ 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_Georeferencing, 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_Georeferencing_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);

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

@@ -0,0 +1,238 @@
+
+/*
+ * 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>({ "Georeferencing" }));
+        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);
+        printf("resultLevel: %f %f %f\n", resultLevel.GetX(), resultLevel.GetY(), resultLevel.GetZ());
+        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();

+ 11 - 0
Gems/LevelGeoreferencing/Code/Tests/Tools/GeoreferencingEditorTest.cpp

@@ -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
+ *
+ */
+
+#include <AzTest/AzTest.h>
+
+AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

+ 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
+)

+ 18 - 0
Gems/LevelGeoreferencing/Registry/assetprocessor_settings.setreg

@@ -0,0 +1,18 @@
+{
+    "Amazon": {
+        "AssetProcessor": {
+            "Settings": {
+                "ScanFolder Georeferencing/Assets": {
+                    "watch": "@GEMROOT:Georeferencing@/Assets",
+                    "recursive": 1,
+                    "order": 101
+                },
+                "ScanFolder Georeferencing/Registry": {
+                    "watch": "@GEMROOT:Georeferencing@/Registry",
+                    "recursive": 1,
+                    "order": 102
+                }
+            }
+        }
+    }
+}

+ 28 - 0
Gems/LevelGeoreferencing/gem.json

@@ -0,0 +1,28 @@
+{
+    "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"
+    ],
+    "platforms": [
+        ""
+    ],
+    "icon_path": "preview.png",
+    "requirements": "",
+    "documentation_url": "https://www.docs.o3de.org/docs/user-guide/interactivity/robotics/georeference/",
+    "dependencies": [],
+    "repo_uri": "",
+    "compatible_engines": [],
+    "engine_api_dependencies": [],
+    "restricted": "Georeferencing"
+}

+ 3 - 0
Gems/LevelGeoreferencing/preview.png

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

+ 1 - 0
Gems/ROS2/Code/CMakeLists.txt

@@ -68,6 +68,7 @@ ly_add_target(
             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 vision_msgs control_msgs)

+ 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.
-    };
-}

+ 4 - 3
Gems/ROS2/Code/Source/GNSS/ROS2GNSSSensorComponent.cpp

@@ -12,9 +12,9 @@
 #include <ROS2/ROS2GemUtilities.h>
 #include <ROS2/Utilities/ROS2Names.h>
 
-#include "Georeference/GNSSFormatConversions.h"
+
 #include <ROS2/GNSS/GNSSPostProcessingRequestBus.h>
-#include <ROS2/Georeference/GeoreferenceBus.h>
+#include <Georeferencing/GeoreferenceBus.h>
 
 namespace ROS2
 {
@@ -94,11 +94,12 @@ namespace ROS2
 
     void ROS2GNSSSensorComponent::FrequencyTick()
     {
+        using namespace Georeferencing;
         AZ::Vector3 currentPosition{ 0.0f };
         AZ::TransformBus::EventResult(currentPosition, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
 
         WGS::WGS84Coordinate currentPositionWGS84;
-        ROS2::GeoreferenceRequestsBus::BroadcastResult(
+        GeoreferenceRequestsBus::BroadcastResult(
             currentPositionWGS84, &GeoreferenceRequests::ConvertFromLevelToWGS84, currentPosition);
 
         m_gnssMsg.latitude = currentPositionWGS84.m_latitude;

+ 0 - 2
Gems/ROS2/Code/Source/ROS2EditorModule.cpp

@@ -9,7 +9,6 @@
 #include <Camera/ROS2CameraSensorEditorComponent.h>
 #include <Camera/ROS2EditorCameraSystemComponent.h>
 #include <Frame/ROS2FrameSystemComponent.h>
-#include <Georeference/GeoreferenceLevelEditorComponent.h>
 #include <Lidar/LidarRegistrarEditorSystemComponent.h>
 #include <Manipulation/JointsManipulationEditorComponent.h>
 #include <Manipulation/JointsPositionsEditorComponent.h>
@@ -52,7 +51,6 @@ namespace ROS2
                   SdfAssetBuilderSystemComponent::CreateDescriptor(),
                   JointsManipulationEditorComponent::CreateDescriptor(),
                   JointsPositionsEditorComponent::CreateDescriptor(),
-                  GeoReferenceLevelEditorComponent::CreateDescriptor(),
                   ROS2FrameSystemComponent::CreateDescriptor(),
                   ROS2FrameEditorComponent::CreateDescriptor() });
         }

+ 0 - 2
Gems/ROS2/Code/Source/ROS2ModuleInterface.h

@@ -14,7 +14,6 @@
 #include <Camera/ROS2CameraSystemComponent.h>
 #include <ContactSensor/ROS2ContactSensorComponent.h>
 #include <GNSS/ROS2GNSSSensorComponent.h>
-#include <Georeference/GeoreferenceLevelComponent.h>
 #include <Gripper/FingerGripperComponent.h>
 #include <Gripper/GripperActionServerComponent.h>
 #include <Gripper/VacuumGripperComponent.h>
@@ -99,7 +98,6 @@ namespace ROS2
                     FingerGripperComponent::CreateDescriptor(),
                     ROS2ContactSensorComponent::CreateDescriptor(),
                     FollowingCameraComponent::CreateDescriptor(),
-                    GeoReferenceLevelComponent::CreateDescriptor(),
                     ClassSegmentationConfigurationComponent::CreateDescriptor(),
                 });
         }

+ 7 - 6
Gems/ROS2/Code/Source/Spawner/ROS2SpawnerComponent.cpp

@@ -15,8 +15,8 @@
 #include <AzCore/std/string/conversions.h>
 #include <AzCore/std/string/string.h>
 #include <AzFramework/Spawnable/Spawnable.h>
+#include <Georeferencing/GeoreferenceBus.h>
 #include <ROS2/Frame/ROS2FrameComponent.h>
-#include <ROS2/Georeference/GeoreferenceBus.h>
 #include <ROS2/ROS2Bus.h>
 #include <ROS2/ROS2GemUtilities.h>
 #include <ROS2/Spawner/SpawnerBus.h>
@@ -126,7 +126,7 @@ namespace ROS2
 
         SpawnEntityResponse response;
 
-        if (isWGS && !GeoreferenceRequestsBus::HasHandlers())
+        if (isWGS && !Georeferencing::GeoreferenceRequestsBus::HasHandlers())
         {
             response.success = false;
             response.status_message = "Level is not geographically positioned. Action aborted.";
@@ -207,15 +207,16 @@ namespace ROS2
 
         if (isWGS)
         {
-            ROS2::WGS::WGS84Coordinate coordinate;
+            Georeferencing::WGS::WGS84Coordinate coordinate;
             AZ::Vector3 coordinateInLevel = AZ::Vector3(-1);
             AZ::Quaternion rotationInENU = AZ::Quaternion::CreateIdentity();
             coordinate.m_latitude = request->initial_pose.position.x;
             coordinate.m_longitude = request->initial_pose.position.y;
             coordinate.m_altitude = request->initial_pose.position.z;
-            ROS2::GeoreferenceRequestsBus::BroadcastResult(rotationInENU, &ROS2::GeoreferenceRequests::GetRotationFromLevelToENU);
-            ROS2::GeoreferenceRequestsBus::BroadcastResult(
-                coordinateInLevel, &ROS2::GeoreferenceRequests::ConvertFromWGS84ToLevel, coordinate);
+            Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+                rotationInENU, &Georeferencing::GeoreferenceRequests::GetRotationFromLevelToENU);
+            Georeferencing::GeoreferenceRequestsBus::BroadcastResult(
+                coordinateInLevel, &Georeferencing::GeoreferenceRequests::ConvertFromWGS84ToLevel, coordinate);
 
             rotationInENU = (rotationInENU.GetInverseFast() *
                              AZ::Quaternion(

+ 0 - 2
Gems/ROS2/Code/ros2_editor_files.cmake

@@ -10,8 +10,6 @@ set(FILES
     Source/Camera/ROS2CameraSensorEditorComponent.h
     Source/Camera/ROS2EditorCameraSystemComponent.cpp
     Source/Camera/ROS2EditorCameraSystemComponent.h
-    Source/Georeference/GeoreferenceLevelEditorComponent.cpp
-    Source/Georeference/GeoreferenceLevelEditorComponent.h
     Source/Lidar/LidarRegistrarEditorSystemComponent.cpp
     Source/Lidar/LidarRegistrarEditorSystemComponent.h
     Source/Manipulation/JointsPositionsEditorComponent.cpp

+ 0 - 5
Gems/ROS2/Code/ros2_files.cmake

@@ -39,9 +39,6 @@ set(FILES
         Source/Frame/ROS2FrameComponent.cpp
         Source/Frame/ROS2FrameConfiguration.cpp
         Source/Frame/ROS2Transform.cpp
-        Source/Georeference/GeoreferenceStructures.cpp
-        Source/Georeference/GeoreferenceLevelComponent.cpp
-        Source/Georeference/GeoreferenceLevelComponent.h
         Source/Gripper/GripperActionServer.cpp
         Source/Gripper/GripperActionServer.h
         Source/Gripper/GripperActionServerComponent.cpp
@@ -50,8 +47,6 @@ set(FILES
         Source/Gripper/VacuumGripperComponent.cpp
         Source/Gripper/FingerGripperComponent.h
         Source/Gripper/FingerGripperComponent.cpp
-        Source/Georeference/GNSSFormatConversions.cpp
-        Source/Georeference/GNSSFormatConversions.h
         Source/GNSS/ROS2GNSSSensorComponent.cpp
         Source/GNSS/ROS2GNSSSensorComponent.h
         Source/Imu/ImuSensorConfiguration.cpp

+ 0 - 3
Gems/ROS2/Code/ros2_header_files.cmake

@@ -18,9 +18,6 @@ set(FILES
         Include/ROS2/Frame/ROS2FrameComponent.h
         Include/ROS2/Frame/ROS2FrameConfiguration.h
         Include/ROS2/Frame/ROS2Transform.h
-        Include/ROS2/Georeference/GeoreferenceBus.h
-        Include/ROS2/Georeference/GeoreferenceStructures.h
-        Include/ROS2/Georeference/GeoreferenceStructures.h
         Include/ROS2/GNSS/GNSSPostProcessingRequestBus.h
         Include/ROS2/Gripper/GripperRequestBus.h
         Include/ROS2/Manipulation/Controllers/JointsPositionControllerRequests.h

+ 0 - 1
Gems/ROS2/Code/ros2_tests_files.cmake

@@ -5,6 +5,5 @@
 
 set(FILES
     Tests/ROS2Test.cpp
-    Tests/GNSSTest.cpp
     Tests/PIDTest.cpp
 )

+ 2 - 1
Gems/ROS2/gem.json

@@ -32,7 +32,8 @@
         "CommonFeaturesAtom",
         "PhysX5",
         "PrimitiveAssets",
-        "StartingPointInput"
+        "StartingPointInput",
+        "LevelGeoreferencing"
     ],
     "restricted": "ROS2",
     "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",