From 3b799fcad92dedd63b858a8a4053f8066c7615f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 17 May 2023 18:51:49 +0200 Subject: [PATCH] python: expose scenetools.filter_objects(). --- doc/python/magnum.scenetools.rst | 4 +++ src/python/magnum/scenetools.cpp | 11 +++++++ src/python/magnum/test/test_scenetools.py | 38 +++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/doc/python/magnum.scenetools.rst b/doc/python/magnum.scenetools.rst index ff71eb5..c4fc42b 100644 --- a/doc/python/magnum.scenetools.rst +++ b/doc/python/magnum.scenetools.rst @@ -35,6 +35,10 @@ :raise AssertionError: If size of any array in :p:`entries_to_keep` does not match :ref:`trade.SceneData.field_size()` for given field +.. py:function:: magnum.scenetools.filter_objects + :raise AssertionError: If size of :p:`objects_to_keep` is different than + :ref:`trade.SceneData.mapping_bound` + .. py:function:: magnum.scenetools.absolute_field_transformations2d :raise KeyError: If :p:`field` does not exist in :p:`scene` :raise IndexError: If :p:`field_id` negative or not less than diff --git a/src/python/magnum/scenetools.cpp b/src/python/magnum/scenetools.cpp index ca35358..50880f6 100644 --- a/src/python/magnum/scenetools.cpp +++ b/src/python/magnum/scenetools.cpp @@ -150,6 +150,17 @@ void scenetools(py::module_& m) { return SceneTools::filterFieldEntries(scene, entriesToKeep); }, "Filter individual entries of fields in a scene", py::arg("scene"), py::arg("entries_to_keep")) + .def("filter_objects", [](const Trade::SceneData& scene, const Containers::BitArrayView objectsToKeep) { + if(objectsToKeep.size() != scene.mappingBound()) { + PyErr_Format(PyExc_AssertionError, "expected %llu bits but got %zu", scene.mappingBound(), objectsToKeep.size()); + throw py::error_already_set{}; + } + /** @todo this will blow up if any objects have a bit / string + field, implement that already so it's not needed to check + here */ + + return SceneTools::filterObjects(scene, objectsToKeep); + }, "Filter objects in a scene", py::arg("scene"), py::arg("objects_to_keep")) .def("absolute_field_transformations2d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation) { const Containers::Optional fieldId = scene.findFieldId(field); if(!fieldId) { diff --git a/src/python/magnum/test/test_scenetools.py b/src/python/magnum/test/test_scenetools.py index dcc2328..e4a440f 100644 --- a/src/python/magnum/test/test_scenetools.py +++ b/src/python/magnum/test/test_scenetools.py @@ -274,6 +274,44 @@ class Filter(unittest.TestCase): (importer.scene_field_for_name('yes'), containers.BitArray.value_init(2)) ]) + def test_objects(self): + importer = trade.ImporterManager().load_and_instantiate('GltfImporter') + importer.open_file(os.path.join(os.path.dirname(__file__), "scene.gltf")) + + scene = importer.scene(0) + scene_refcount = sys.getrefcount(scene) + self.assertEqual(scene.mapping_bound, 4) + self.assertEqual(scene.field_count, 8) + self.assertEqual(scene.field_size(trade.SceneField.PARENT), 4) + self.assertEqual(scene.field_size(trade.SceneField.TRANSFORMATION), 4) + self.assertEqual(scene.field_size(trade.SceneField.TRANSLATION), 3) + self.assertEqual(scene.field_size(trade.SceneField.CAMERA), 2) + + # Two parents, transformations and translations gone + objects_to_keep = containers.BitArray.direct_init(scene.mapping_bound, True) + objects_to_keep[0] = False + objects_to_keep[1] = False + + filtered = scenetools.filter_objects(scene, objects_to_keep) + self.assertEqual(filtered.mapping_bound, 4) + self.assertEqual(filtered.field_count, 8) + self.assertEqual(filtered.field_size(trade.SceneField.PARENT), 2) + self.assertEqual(filtered.field_size(trade.SceneField.TRANSFORMATION), 2) + self.assertEqual(filtered.field_size(trade.SceneField.TRANSLATION), 1) + self.assertEqual(filtered.field_size(trade.SceneField.CAMERA), 2) + # The original scene isn't referenced by this one, it's a full copy + self.assertEqual(sys.getrefcount(scene), scene_refcount) + + def test_objects_invalid_size(self): + importer = trade.ImporterManager().load_and_instantiate('GltfImporter') + importer.open_file(os.path.join(os.path.dirname(__file__), "scene.gltf")) + + scene = importer.scene(0) + self.assertEqual(scene.mapping_bound, 4) + + with self.assertRaisesRegex(AssertionError, "expected 4 bits but got 3"): + scenetools.filter_objects(scene, containers.BitArray.value_init(3)) + class Hierarchy(unittest.TestCase): def test_absolute_field_transformations2d(self): # Static builds with non-static plugins cause assertions with non-owned