@@ -378,13 +378,21 @@ def add_multiscales_metadata_to_parent(
378378 log .info ("No CRS found, skipping multiscales metadata" , base_path = group .path )
379379 return None
380380
381- native_bounds = None
382- try :
383- native_bounds = first_dataset .rio .bounds ()
384- except (AttributeError , TypeError ):
385- x_coords = first_dataset .x .values
386- y_coords = first_dataset .y .values
387- native_bounds = (x_coords .min (), y_coords .min (), x_coords .max (), y_coords .max ())
381+ # Calculate bounds directly from coordinates for consistency with the data arrays
382+ if "x" not in first_dataset .coords or "y" not in first_dataset .coords :
383+ log .error (
384+ "Missing x/y coordinates in dataset, cannot determine bounds" , base_path = group .path
385+ )
386+ return None
387+
388+ x_coords = first_dataset .x .values
389+ y_coords = first_dataset .y .values
390+ native_bounds = (
391+ float (x_coords .min ()),
392+ float (y_coords .min ()),
393+ float (x_coords .max ()),
394+ float (y_coords .max ()),
395+ )
388396
389397 # Create overview_levels structure following the multiscales v1.0 specification
390398 overview_levels : list [OverviewLevelJSON ] = []
@@ -424,8 +432,10 @@ def add_multiscales_metadata_to_parent(
424432 y_coords = dataset .coords ["y" ].values
425433
426434 if len (x_coords ) > 1 and len (y_coords ) > 1 :
435+ # Calculate pixel size from actual coordinate spacing
427436 pixel_size_x = float (np .abs (x_coords [1 ] - x_coords [0 ]))
428437 pixel_size_y = float (np .abs (y_coords [1 ] - y_coords [0 ]))
438+
429439 x_min = float (x_coords .min ())
430440 y_max = float (y_coords .max ())
431441 transform = (pixel_size_x , 0.0 , x_min , 0.0 , - pixel_size_y , y_max )
@@ -456,10 +466,60 @@ def add_multiscales_metadata_to_parent(
456466 zoom_for_height = max (0 , int (np .ceil (np .log2 (height / tile_width ))))
457467 zoom = max (zoom_for_width , zoom_for_height )
458468
459- # Calculate relative scale and translation vs first resolution
469+ # Calculate relative scale and translation vs parent resolution
460470 finest_res_meters = res_order [all_resolutions [0 ]]
461- relative_scale = res_meters / finest_res_meters
462- relative_translation = (res_meters - finest_res_meters ) / 2
471+
472+ # Fix for issue #114: Translation values should be 0
473+ relative_translation = 0.0
474+
475+ # Calculate proper relative scale based on actual parent-child dimension ratios
476+ if res_name == all_resolutions [0 ]: # Base resolution
477+ relative_scale = 1.0
478+ else :
479+ # Define derivation chain to find parent resolution
480+ derivation_chain = {
481+ "r10m" : None ,
482+ "r20m" : "r10m" ,
483+ "r60m" : "r10m" ,
484+ "r120m" : "r60m" ,
485+ "r360m" : "r120m" ,
486+ "r720m" : "r360m" ,
487+ }
488+
489+ parent_res = derivation_chain .get (res_name )
490+ if parent_res and parent_res in res_groups :
491+ # Get actual dimensions of parent and child
492+ parent_dataset = res_groups [parent_res ]
493+ parent_var = next (iter (parent_dataset .data_vars .values ()))
494+ parent_height , parent_width = parent_var .shape [- 2 :]
495+
496+ # Current (child) dimensions
497+ child_height , child_width = height , width
498+
499+ # Calculate actual scale ratio based on dimensions
500+ # Use the larger of the two ratios to be conservative
501+ scale_x = parent_width / child_width if child_width > 0 else 1.0
502+ scale_y = parent_height / child_height if child_height > 0 else 1.0
503+ relative_scale = max (scale_x , scale_y )
504+
505+ log .info (
506+ "Calculated dynamic scale ratio" ,
507+ level = res_name ,
508+ parent = parent_res ,
509+ parent_dims = (parent_height , parent_width ),
510+ child_dims = (child_height , child_width ),
511+ scale_x = scale_x ,
512+ scale_y = scale_y ,
513+ relative_scale = relative_scale ,
514+ )
515+ else :
516+ # Fallback to absolute resolution ratio
517+ relative_scale = res_meters / finest_res_meters
518+ log .warning (
519+ "Using fallback scale calculation" ,
520+ level = res_name ,
521+ relative_scale = relative_scale ,
522+ )
463523
464524 # Get chunks in the correct format
465525 var_chunks = dataset .data_vars [first_var .name ].chunks
0 commit comments