@@ -875,15 +875,60 @@ def get_map_with_name_ref(self, name, data):
875875 # Old 180° rotation (incorrect - missing transpose, caused 90° CCW error in RViz):
876876 # m = xp.flip(m, 0)
877877 # m = xp.flip(m, 1)
878- m = m .T
879- m = xp .flip (m , 0 )
880- m = xp .flip (m , 1 )
878+ m = self ._transform_to_grid_map_coordinate_convention (m )
881879 if use_stream :
882880 stream = cp .cuda .Stream (non_blocking = False )
883881 else :
884882 stream = None
885883 self .copy_to_cpu (m , data , stream = stream )
886884
885+ def _transform_to_grid_map_coordinate_convention (self , m ):
886+ """Transform the map to the grid_map coordinate convention.
887+
888+ elevation_mapping_cupy uses Row=Y, Col=X (see kernels/custom_kernels.py:35)
889+ grid_map uses Row→-X, Col→-Y (see grid_map_core/src/GridMapMath.cpp:64-67
890+ transformBufferOrderToMapFrame returns {-index[0], -index[1]})
891+ Required transformation:
892+ 1. Transpose: swap axes so Row=X, Col=Y (matching grid_map's axis assignment)
893+ 2. Flip axis 0: so increasing row → decreasing X (matching grid_map's -X)
894+ 3. Flip axis 1: so increasing col → decreasing Y (matching grid_map's -Y)
895+
896+ This is equivalent to: rot90(m.T, k=2) or flip(flip(m.T, 0), 1)
897+
898+ Args:
899+ m (cupy._core.core.ndarray):
900+
901+ Returns:
902+ cupy._core.core.ndarray:
903+ """
904+ m = m .T
905+ m = xp .flip (m , 0 )
906+ m = xp .flip (m , 1 )
907+ return m
908+
909+ def _transform_to_elevation_mapping_coordinate_convention (self , m ):
910+ """Transform the map to the grid_map coordinate convention.
911+
912+ elevation_mapping_cupy uses Row=Y, Col=X (see kernels/custom_kernels.py:35)
913+ grid_map uses Row→-X, Col→-Y (see grid_map_core/src/GridMapMath.cpp:64-67
914+ transformBufferOrderToMapFrame returns {-index[0], -index[1]})
915+ To transform back to a normal array, we need to apply the inverse transformation:
916+ Flip axis 0: so increasing row → decreasing X (matching grid_map's -X)
917+ Flip axis 1: so increasing col → decreasing Y (matching grid_map's -Y)
918+ Transpose: swap axes so Row=X, Col=Y (matching grid_map's axis assignment)
919+ This is equivalent to: flip(flip(m, 0), 1).T
920+
921+ Args:
922+ m (cupy._core.core.ndarray):
923+
924+ Returns:
925+ cupy._core.core.ndarray:
926+ """
927+ m = xp .flip (m , 0 )
928+ m = xp .flip (m , 1 )
929+ m = m .T
930+ return m
931+
887932 def get_normal_maps (self ):
888933 """Get the normal maps.
889934
@@ -1062,6 +1107,12 @@ def apply_masked_replace(
10621107 if not layer_data :
10631108 raise ValueError ("No layer data provided for masked replace." )
10641109
1110+ # Transform the layer data from grid_map coordinate convention to the elevation_mapping_cupy coordinate convention
1111+ for name , array in layer_data .items ():
1112+ layer_data [name ] = self ._transform_to_elevation_mapping_coordinate_convention (array )
1113+ if mask is not None :
1114+ mask = self ._transform_to_elevation_mapping_coordinate_convention (mask )
1115+
10651116 sample_shape : Optional [Tuple [int , int ]] = None
10661117 for array in layer_data .values ():
10671118 if sample_shape is None :
@@ -1134,6 +1185,11 @@ def set_full_map(
11341185 ) -> None :
11351186 if not raw_layers :
11361187 raise ValueError ("Raw layer data required to restore the map." )
1188+
1189+ # Transform the raw layer data from grid_map coordinate convention to the elevation_mapping_cupy coordinate convention
1190+ for name , array in raw_layers .items ():
1191+ raw_layers [name ] = self ._transform_to_elevation_mapping_coordinate_convention (array )
1192+
11371193 sample_shape = next (iter (raw_layers .values ())).shape
11381194 self ._validate_geometry_against_shape (sample_shape , geometry )
11391195
0 commit comments