Browse Source

python: adapt to SceneTools and MeshTools changes.

Breaking changes, sorry. Also remade the SceneTools hierarchy test to
not be that much redundant -- the name- and ID-based overloads can be
tested together.
next
Vladimír Vondruš 3 years ago
parent
commit
949820b01a
  1. 4
      doc/python/magnum.scenetools.rst
  2. 5
      doc/python/pages/changelog.rst
  3. 2
      modules/FindMagnum.cmake
  4. 6
      src/python/magnum/meshtools.cpp
  5. 26
      src/python/magnum/scenetools.cpp
  6. 10
      src/python/magnum/test/test_meshtools.py
  7. 83
      src/python/magnum/test/test_scenetools.py

4
doc/python/magnum.scenetools.rst

@ -23,7 +23,7 @@
DEALINGS IN THE SOFTWARE.
..
.. py:function:: magnum.scenetools.flatten_transformation_hierarchy2d
.. 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
:ref:`trade.SceneData.field_count`
@ -31,7 +31,7 @@
:raise AssertionError: If :p:`scene` does not have
:ref:`trade.SceneField.PARENT`
.. py:function:: magnum.scenetools.flatten_transformation_hierarchy3d
.. py:function:: magnum.scenetools.absolute_field_transformations3d
:raise KeyError: If :p:`field` does not exist in :p:`scene`
:raise IndexError: If :p:`field_id` negative or not less than
:ref:`trade.SceneData.field_count`

5
doc/python/pages/changelog.rst

@ -108,10 +108,11 @@ Changelog
:ref:`platform.glfw.Application.InputEvent.Modifier` to behave properly
as flags and not just as an enum
- Exposed :ref:`meshtools.compress_indices()`, :ref:`meshtools.concatenate()`,
:ref:`meshtools.duplicate()`, :ref:`meshtools.filter_except_attributes()`,
:ref:`meshtools.copy()`, :ref:`meshtools.duplicate()`,
:ref:`meshtools.filter_except_attributes()`,
:ref:`meshtools.filter_only_attributes()`,
:ref:`meshtools.generate_indices()`, :ref:`meshtools.interleave()`,
:ref:`meshtools.owned()`, :ref:`meshtools.remove_duplicates()`,
:ref:`meshtools.remove_duplicates()`,
:ref:`meshtools.remove_duplicates_fuzzy()`, :ref:`meshtools.transform2d()`,
:ref:`meshtools.transform2d_in_place()`, :ref:`meshtools.transform3d()`,
:ref:`meshtools.transform3d_in_place()`,

2
modules/FindMagnum.cmake

@ -910,7 +910,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
# SceneTools library
elseif(_component STREQUAL SceneTools)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES FlattenTransformationHierarchy.h)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Hierarchy.h)
# ShaderTools library
elseif(_component STREQUAL ShaderTools)

6
src/python/magnum/meshtools.cpp

@ -30,13 +30,13 @@
#include <Magnum/GL/Mesh.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/MeshTools/Copy.h>
#include <Magnum/MeshTools/Concatenate.h>
#include <Magnum/MeshTools/Duplicate.h>
#include <Magnum/MeshTools/FilterAttributes.h>
#include <Magnum/MeshTools/Filter.h>
#include <Magnum/MeshTools/GenerateIndices.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/RemoveDuplicates.h>
#include <Magnum/MeshTools/Reference.h>
#include <Magnum/MeshTools/Transform.h>
#include <Magnum/Trade/MeshData.h>
@ -163,7 +163,7 @@ void meshtools(py::module_& m) {
test */
return MeshTools::interleave(mesh, {}, flags);
}, "Interleave mesh data", py::arg("mesh"), py::arg("flags") = MeshTools::InterleaveFlag::PreserveInterleavedAttributes)
.def("owned", static_cast<Trade::MeshData(*)(const Trade::MeshData&)>(MeshTools::owned), "Create an owned mesh data", py::arg("mesh"))
.def("copy", static_cast<Trade::MeshData(*)(const Trade::MeshData&)>(MeshTools::copy), "Make a owned copy of the mesh", py::arg("mesh"))
/** @todo check that the indices/vertices aren't impl-specific once
it's possible to test */
.def("remove_duplicates", static_cast<Trade::MeshData(*)(const Trade::MeshData&)>(MeshTools::removeDuplicates), "Remove mesh data duplicates", py::arg("mesh"))

26
src/python/magnum/scenetools.cpp

@ -29,7 +29,7 @@
#include <Corrade/Containers/ArrayViewStl.h>
#include <Magnum/Math/Matrix3.h>
#include <Magnum/Math/Matrix4.h>
#include <Magnum/SceneTools/FlattenTransformationHierarchy.h>
#include <Magnum/SceneTools/Hierarchy.h>
#include <Magnum/Trade/SceneData.h>
#include "magnum/bootstrap.h"
@ -46,7 +46,7 @@ void scenetools(py::module_& m) {
#endif
m
.def("flatten_transformation_hierarchy2d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation) {
.def("absolute_field_transformations2d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation) {
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field);
if(!fieldId) {
PyErr_SetNone(PyExc_KeyError);
@ -63,10 +63,10 @@ void scenetools(py::module_& m) {
/** @todo maybe do a caster for arrays, finally?! */
std::vector<Matrix3> out(scene.fieldSize(*fieldId));
SceneTools::flattenTransformationHierarchy2DInto(scene, *fieldId, out, globalTransformation);
SceneTools::absoluteFieldTransformations2DInto(scene, *fieldId, out, globalTransformation);
return out;
}, "Flatten a 2D transformation hierarchy for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix3{})
.def("flatten_transformation_hierarchy2d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation) {
}, "Calculate absolute 2D transformations for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix3{})
.def("absolute_field_transformations2d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation) {
if(fieldId >= scene.fieldCount()) {
PyErr_SetNone(PyExc_IndexError);
throw py::error_already_set{};
@ -82,10 +82,10 @@ void scenetools(py::module_& m) {
/** @todo maybe do a caster for arrays, finally?! */
std::vector<Matrix3> out(scene.fieldSize(fieldId));
SceneTools::flattenTransformationHierarchy2DInto(scene, fieldId, out, globalTransformation);
SceneTools::absoluteFieldTransformations2DInto(scene, fieldId, out, globalTransformation);
return out;
}, "Flatten a 2D transformation hierarchy for given field ID", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix3{})
.def("flatten_transformation_hierarchy3d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation) {
}, "Calculate absolute 2D transformations for given named field", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix3{})
.def("absolute_field_transformations3d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation) {
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field);
if(!fieldId) {
PyErr_SetNone(PyExc_KeyError);
@ -102,10 +102,10 @@ void scenetools(py::module_& m) {
/** @todo maybe do a caster for arrays, finally?! */
std::vector<Matrix4> out(scene.fieldSize(*fieldId));
SceneTools::flattenTransformationHierarchy3DInto(scene, *fieldId, out, globalTransformation);
SceneTools::absoluteFieldTransformations3DInto(scene, *fieldId, out, globalTransformation);
return out;
}, "Flatten a 3D transformation hierarchy for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix4{})
.def("flatten_transformation_hierarchy3d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation) {
}, "Calculate absolute 3D transformations for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix4{})
.def("absolute_field_transformations3d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation) {
if(fieldId >= scene.fieldCount()) {
PyErr_SetNone(PyExc_IndexError);
throw py::error_already_set{};
@ -121,9 +121,9 @@ void scenetools(py::module_& m) {
/** @todo maybe do a caster for arrays, finally?! */
std::vector<Matrix4> out(scene.fieldSize(fieldId));
SceneTools::flattenTransformationHierarchy3DInto(scene, fieldId, out, globalTransformation);
SceneTools::absoluteFieldTransformations3DInto(scene, fieldId, out, globalTransformation);
return out;
}, "Flatten a 3D transformation hierarchy for given field ID", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix4{});
}, "Calculate absolute 2D transformations for given named field", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix4{});
}
}

10
src/python/magnum/test/test_meshtools.py

@ -180,13 +180,13 @@ class Interleave(unittest.TestCase):
# Gap after normals removed
self.assertEqual(interleaved_packed.attribute_stride(trade.MeshAttribute.POSITION), 12 + 8)
class Owned(unittest.TestCase):
class Copy(unittest.TestCase):
def test(self):
mesh = primitives.square_solid()
self.assertEqual(mesh.vertex_data_flags, trade.DataFlags.GLOBAL)
owned = meshtools.owned(mesh)
self.assertEqual(owned.vertex_data_flags, trade.DataFlags.OWNED|trade.DataFlags.MUTABLE)
copy = meshtools.copy(mesh)
self.assertEqual(copy.vertex_data_flags, trade.DataFlags.OWNED|trade.DataFlags.MUTABLE)
class RemoveDuplicates(unittest.TestCase):
def test(self):
@ -248,14 +248,14 @@ class Transform(unittest.TestCase):
self.assertEqual(transformed.attribute(trade.MeshAttribute.TEXTURE_COORDINATES)[0], (101.0, 0.0))
def test_texture_coordinates2d_in_place(self):
mesh = meshtools.owned(primitives.square_solid(primitives.SquareFlags.TEXTURE_COORDINATES))
mesh = meshtools.copy(primitives.square_solid(primitives.SquareFlags.TEXTURE_COORDINATES))
self.assertEqual(mesh.attribute(trade.MeshAttribute.TEXTURE_COORDINATES)[0], (1.0, 0.0))
meshtools.transform_texture_coordinates2d_in_place(mesh, Matrix3.translation(Vector2.x_axis(100.0)))
self.assertEqual(mesh.attribute(trade.MeshAttribute.TEXTURE_COORDINATES)[0], (101.0, 0.0))
def test_no_attribute(self):
mesh = meshtools.owned(primitives.square_solid(primitives.SquareFlags.TEXTURE_COORDINATES))
mesh = meshtools.copy(primitives.square_solid(primitives.SquareFlags.TEXTURE_COORDINATES))
with self.assertRaisesRegex(KeyError, "position attribute not found"):
meshtools.transform2d(mesh, Matrix3(), 1)

83
src/python/magnum/test/test_scenetools.py

@ -30,8 +30,8 @@ from magnum import *
from magnum import scenetools, trade
import magnum
class FlattenTransformationHierarchy(unittest.TestCase):
def test_2d(self):
class Hierarchy(unittest.TestCase):
def test_absolute_field_transformations2d(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
@ -44,30 +44,14 @@ class FlattenTransformationHierarchy(unittest.TestCase):
scene = importer.scene(0)
self.assertTrue(scene.is_2d)
transformations = scenetools.flatten_transformation_hierarchy2d(scene, trade.SceneField.MESH)
self.assertEqual(len(transformations), scene.field_size(trade.SceneField.MESH))
self.assertEqual(transformations[0], Matrix3.translation((-4.5, -3.0)))
transformations1 = scenetools.absolute_field_transformations2d(scene, trade.SceneField.MESH)
transformations2 = scenetools.absolute_field_transformations2d(scene, scene.field_id(trade.SceneField.MESH))
self.assertEqual(len(transformations1), scene.field_size(trade.SceneField.MESH))
self.assertEqual(len(transformations2), scene.field_size(trade.SceneField.MESH))
self.assertEqual(transformations1[0], Matrix3.translation((-4.5, -3.0)))
self.assertEqual(transformations2[0], Matrix3.translation((-4.5, -3.0)))
def test_2d_field_id(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
self.skipTest("dynamic PrimitiveImporter doesn't work with a static build")
# The only way to get a 2D scene is via PrimitiveImporter
importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter')
importer.open_data(containers.ArrayView())
scene = importer.scene(0)
self.assertTrue(scene.is_2d)
mesh_field = scene.field_id(trade.SceneField.MESH)
transformations = scenetools.flatten_transformation_hierarchy2d(scene, mesh_field)
self.assertEqual(len(transformations), scene.field_size(mesh_field))
self.assertEqual(transformations[0], Matrix3.translation((-4.5, -3.0)))
def test_3d(self):
def test_absolute_field_transformations3d(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
@ -79,29 +63,14 @@ class FlattenTransformationHierarchy(unittest.TestCase):
scene = importer.scene(1)
self.assertTrue(scene.is_3d)
transformations = scenetools.flatten_transformation_hierarchy3d(scene, trade.SceneField.MESH)
self.assertEqual(len(transformations), scene.field_size(trade.SceneField.MESH))
self.assertEqual(transformations[0], Matrix4.translation((-4.5, -3.0, 0.0)))
def test_3d_field_id(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
self.skipTest("dynamic PrimitiveImporter doesn't work with a static build")
importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter')
importer.open_data(containers.ArrayView())
scene = importer.scene(1)
self.assertTrue(scene.is_3d)
mesh_field = scene.field_id(trade.SceneField.MESH)
transformations = scenetools.flatten_transformation_hierarchy3d(scene, mesh_field)
self.assertEqual(len(transformations), scene.field_size(mesh_field))
self.assertEqual(transformations[0], Matrix4.translation((-4.5, -3.0, 0.0)))
transformations1 = scenetools.absolute_field_transformations3d(scene, trade.SceneField.MESH)
transformations2 = scenetools.absolute_field_transformations3d(scene, scene.field_id(trade.SceneField.MESH))
self.assertEqual(len(transformations1), scene.field_size(trade.SceneField.MESH))
self.assertEqual(len(transformations2), scene.field_size(trade.SceneField.MESH))
self.assertEqual(transformations1[0], Matrix4.translation((-4.5, -3.0, 0.0)))
self.assertEqual(transformations2[0], Matrix4.translation((-4.5, -3.0, 0.0)))
def test_field_not_found(self):
def test_absolute_field_transformations_not_found(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
@ -113,15 +82,15 @@ class FlattenTransformationHierarchy(unittest.TestCase):
scene = importer.scene(0)
with self.assertRaises(KeyError):
scenetools.flatten_transformation_hierarchy2d(scene, trade.SceneField.LIGHT)
scenetools.absolute_field_transformations2d(scene, trade.SceneField.LIGHT)
with self.assertRaises(KeyError):
scenetools.flatten_transformation_hierarchy3d(scene, trade.SceneField.LIGHT)
scenetools.absolute_field_transformations3d(scene, trade.SceneField.LIGHT)
with self.assertRaises(IndexError):
scenetools.flatten_transformation_hierarchy2d(scene, scene.field_count)
scenetools.absolute_field_transformations2d(scene, scene.field_count)
with self.assertRaises(IndexError):
scenetools.flatten_transformation_hierarchy3d(scene, scene.field_count)
scenetools.absolute_field_transformations3d(scene, scene.field_count)
def test_not_2d_not_3d(self):
def test_absolute_field_transformations_not_2d_not_3d(self):
# Static builds with non-static plugins cause assertions with non-owned
# array deleters used by PrimitiveImporter, skip in that case
if magnum.BUILD_STATIC:
@ -136,15 +105,15 @@ class FlattenTransformationHierarchy(unittest.TestCase):
self.assertFalse(scene3d.is_2d)
with self.assertRaisesRegex(AssertionError, "the scene is not 2D"):
scenetools.flatten_transformation_hierarchy2d(scene3d, trade.SceneField.MESH)
scenetools.absolute_field_transformations2d(scene3d, trade.SceneField.MESH)
with self.assertRaisesRegex(AssertionError, "the scene is not 2D"):
scenetools.flatten_transformation_hierarchy2d(scene3d, scene2d.field_id(trade.SceneField.MESH))
scenetools.absolute_field_transformations2d(scene3d, scene2d.field_id(trade.SceneField.MESH))
with self.assertRaisesRegex(AssertionError, "the scene is not 3D"):
scenetools.flatten_transformation_hierarchy3d(scene2d, trade.SceneField.MESH)
scenetools.absolute_field_transformations3d(scene2d, trade.SceneField.MESH)
with self.assertRaisesRegex(AssertionError, "the scene is not 3D"):
scenetools.flatten_transformation_hierarchy3d(scene2d, scene3d.field_id(trade.SceneField.MESH))
scenetools.absolute_field_transformations3d(scene2d, scene3d.field_id(trade.SceneField.MESH))
def test_no_hierarchy(self):
def test_absolute_field_transformations_no_hierarchy(self):
# TODO implement once it's possible to create / import a scene without
# the parent field
pass

Loading…
Cancel
Save