Repository: scalableminds/webknossos-libs

Issue:
Allow explicitly setting a layer's bounding box
For example, when one cuts data away and knows that the bounding box needs to be shrunken, there is no way of setting the box explicitly with the api.


Discussion:

Resolving patch:
diff --git a/wkcuber/api/Layer.py b/wkcuber/api/Layer.py
--- a/wkcuber/api/Layer.py
+++ b/wkcuber/api/Layer.py
@@ -1,6 +1,10 @@
 from shutil import rmtree
 from os.path import join
 from os import makedirs
+from typing import Tuple
+
+import numpy as np
+
 from wkw import wkw
 
 from wkcuber.api.MagDataset import (
@@ -61,6 +65,28 @@ def _assert_mag_does_not_exist_yet(self, mag):
                 )
             )
 
+    def set_bounding_box(
+        self, offset: Tuple[int, int, int], size: Tuple[int, int, int]
+    ):
+        self.set_bounding_box_offset(offset)
+        self.set_bounding_box_size(size)
+
+    def set_bounding_box_offset(self, offset: Tuple[int, int, int]):
+        size = self.dataset.properties.data_layers["color"].get_bounding_box_size()
+        self.dataset.properties._set_bounding_box_of_layer(
+            self.name, tuple(offset), tuple(size)
+        )
+        for _, mag in self.mags.items():
+            mag.view.global_offset = offset
+
+    def set_bounding_box_size(self, size: Tuple[int, int, int]):
+        offset = self.dataset.properties.data_layers["color"].get_bounding_box_offset()
+        self.dataset.properties._set_bounding_box_of_layer(
+            self.name, tuple(offset), tuple(size)
+        )
+        for _, mag in self.mags.items():
+            mag.view.size = size
+
 
 class WKLayer(Layer):
     def add_mag(


Test patch:
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -1146,3 +1146,52 @@ def test_tiled_tiff_dataset_get_or_create():
         raise Exception(expected_error_msg)
     except AssertionError:
         pass
+
+
+def test_changing_layer_bounding_box():
+    delete_dir("./testoutput/test_changing_layer_bounding_box/")
+    copytree(
+        "./testdata/simple_tiff_dataset/",
+        "./testoutput/test_changing_layer_bounding_box/",
+    )
+
+    ds = TiffDataset("./testoutput/test_changing_layer_bounding_box/")
+    layer = ds.get_layer("color")
+    mag = layer.get_mag("1")
+
+    bbox_size = ds.properties.data_layers["color"].get_bounding_box_size()
+    assert bbox_size == (265, 265, 10)
+    original_data = mag.read(bbox_size)
+    assert original_data.shape == (1, 265, 265, 10)
+
+    layer.set_bounding_box_size((100, 100, 10))  # decrease boundingbox
+
+    bbox_size = ds.properties.data_layers["color"].get_bounding_box_size()
+    assert bbox_size == (100, 100, 10)
+    less_data = mag.read(bbox_size)
+    assert less_data.shape == (1, 100, 100, 10)
+    assert np.array_equal(original_data[:, :100, :100, :10], less_data)
+
+    layer.set_bounding_box_size((300, 300, 10))  # increase the boundingbox
+
+    bbox_size = ds.properties.data_layers["color"].get_bounding_box_size()
+    assert bbox_size == (300, 300, 10)
+    more_data = mag.read(bbox_size)
+    assert more_data.shape == (1, 300, 300, 10)
+    assert np.array_equal(more_data[:, :265, :265, :10], original_data)
+
+    layer.set_bounding_box_size((300, 300, 10))  # increase the boundingbox
+
+    assert ds.properties.data_layers["color"].get_bounding_box_offset() == (0, 0, 0)
+
+    layer.set_bounding_box(
+        offset=(10, 10, 0), size=(255, 255, 10)
+    )  # change offset and size
+
+    new_bbox_offset = ds.properties.data_layers["color"].get_bounding_box_offset()
+    new_bbox_size = ds.properties.data_layers["color"].get_bounding_box_size()
+    assert new_bbox_offset == (10, 10, 0)
+    assert new_bbox_size == (255, 255, 10)
+    new_data = mag.read(new_bbox_size)
+    assert new_data.shape == (1, 255, 255, 10)
+    assert np.array_equal(original_data[:, 10:, 10:, :], new_data)