diff --git a/src/Magnum/MeshTools/RemoveDuplicates.cpp b/src/Magnum/MeshTools/RemoveDuplicates.cpp index 965ee0a28..6e6e3230b 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.cpp +++ b/src/Magnum/MeshTools/RemoveDuplicates.cpp @@ -157,4 +157,16 @@ std::size_t removeDuplicatesIndexedInPlace(const Containers::StridedArrayView1D< return removeDuplicatesIndexedInPlaceImplementation(indices, data); } +std::size_t removeDuplicatesIndexedInPlace(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView2D& data) { + CORRADE_ASSERT(indices.isContiguous<1>(), "MeshTools::removeDuplicatesIndexedInPlace(): second index view dimension is not contiguous", {}); + if(indices.size()[1] == 4) + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedInt>(indices), data); + else if(indices.size()[1] == 2) + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedShort>(indices), data); + else { + CORRADE_ASSERT(indices.size()[1] == 1, "MeshTools::removeDuplicatesIndexedInPlace(): expected index type size 1, 2 or 4 but got" << indices.size()[1], {}); + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedByte>(indices), data); + } +} + }} diff --git a/src/Magnum/MeshTools/RemoveDuplicates.h b/src/Magnum/MeshTools/RemoveDuplicates.h index b284282cc..492b8fe7c 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.h +++ b/src/Magnum/MeshTools/RemoveDuplicates.h @@ -145,6 +145,17 @@ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesIndexedInPlace(const Contain */ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesIndexedInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView2D& data); +/** +@brief Remove duplicates from indexed data in-place on a type-erased index array +@m_since_latest + +Expects that the second dimension of @p indices is contiguous and represents +the actual 1/2/4-byte index type. Based on its size then calls one of the +@ref removeDuplicatesIndexedInPlace(const Containers::StridedArrayView1D&) +etc. overloads. +*/ +MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesIndexedInPlace(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView2D& data); + /** @brief Remove duplicate floating-point vector data from given array in-place @param[in,out] data Data array, duplicate items will be cut away with order @@ -273,6 +284,27 @@ template std::size_t removeDuplicatesIndexedInPla return dataSize; } +/** +@brief Remove duplicates from indexed data in-place on a type-erased index array +@m_since_latest + +Expects that the second dimension of @p indices is contiguous and represents +the actual 1/2/4-byte index type. Based on its size then calls +@ref removeDuplicatesIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, typename Vector::Type) +with a concrete index type. +*/ +template std::size_t removeDuplicatesIndexedInPlace(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView1D& data, typename Vector::Type epsilon = Math::TypeTraits::epsilon()) { + CORRADE_ASSERT(indices.isContiguous<1>(), "MeshTools::removeDuplicatesIndexedInPlace(): second index view dimension is not contiguous", {}); + if(indices.size()[1] == 4) + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedInt>(indices), data, epsilon); + else if(indices.size()[1] == 2) + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedShort>(indices), data, epsilon); + else { + CORRADE_ASSERT(indices.size()[1] == 1, "MeshTools::removeDuplicatesIndexedInPlace(): expected index type size 1, 2 or 4 but got" << indices.size()[1], {}); + return removeDuplicatesIndexedInPlace(Containers::arrayCast<1, UnsignedByte>(indices), data, epsilon); + } +} + template std::pair, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView1D& data, typename Vector::Type epsilon) { /* A trivial index array that'll be remapped and returned after */ Containers::Array indices{Containers::NoInit, data.size()}; diff --git a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp index aa96b29f4..d4d5aea9f 100644 --- a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp +++ b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp @@ -43,6 +43,9 @@ struct RemoveDuplicatesTest: TestSuite::Tester { void removeDuplicatesIndexedInPlaceSmallType(); void removeDuplicatesIndexedInPlaceEmptyIndices(); void removeDuplicatesIndexedInPlaceEmptyIndicesVertices(); + template void removeDuplicatesIndexedInPlaceErased(); + void removeDuplicatesIndexedInPlaceErasedNonContiguous(); + void removeDuplicatesIndexedInPlaceErasedWrongIndexSize(); void removeDuplicatesFuzzyInPlace(); #ifdef MAGNUM_BUILD_DEPRECATED @@ -52,6 +55,9 @@ struct RemoveDuplicatesTest: TestSuite::Tester { void removeDuplicatesFuzzyIndexedInPlaceSmallType(); void removeDuplicatesFuzzyIndexedInPlaceEmptyIndices(); void removeDuplicatesFuzzyIndexedInPlaceEmptyIndicesVertices(); + template void removeDuplicatesFuzzyIndexedInPlaceErased(); + void removeDuplicatesFuzzyIndexedInPlaceErasedNonContiguous(); + void removeDuplicatesFuzzyIndexedInPlaceErasedWrongIndexSize(); /* this is additionally regression-tested in PrimitivesIcosphereTest */ }; @@ -66,6 +72,11 @@ RemoveDuplicatesTest::RemoveDuplicatesTest() { &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceSmallType, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceEmptyIndices, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceEmptyIndicesVertices, + &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErasedNonContiguous, + &RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErasedWrongIndexSize, &RemoveDuplicatesTest::removeDuplicatesFuzzyInPlace, #ifdef MAGNUM_BUILD_DEPRECATED @@ -76,7 +87,12 @@ RemoveDuplicatesTest::RemoveDuplicatesTest() { &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlace, &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceSmallType, &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceEmptyIndices, - &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceEmptyIndicesVertices}); + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceEmptyIndicesVertices, + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErased, + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErasedNonContiguous, + &RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErasedWrongIndexSize}); } void RemoveDuplicatesTest::removeDuplicates() { @@ -183,6 +199,57 @@ void RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceEmptyIndicesVertices() Containers::StridedArrayView1D{}, {}), 0); } +template void RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErased() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + T indices[]{3, 2, 0, 1, 7, 6, 4, 2, 5, 0}; + Int data[]{-15, 32, 24, -15, 15, 7541, 24, 32}; + std::size_t count = MeshTools::removeDuplicatesIndexedInPlace( + Containers::arrayCast<2, char>(Containers::arrayView(indices)), + Containers::arrayCast<2, char>(Containers::arrayView(data))); + + CORRADE_COMPARE_AS(Containers::arrayView(indices), + Containers::arrayView({0, 2, 0, 1, 1, 2, 3, 2, 4, 0}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(Containers::arrayView(data).prefix(count), + Containers::arrayView({-15, 32, 24, 15, 7541}), + TestSuite::Compare::Container); +} + +void RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErasedNonContiguous() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + char indices[6*4]{}; + Int data[1]{}; + + std::stringstream out; + Error redirectError{&out}; + MeshTools::removeDuplicatesIndexedInPlace( + Containers::StridedArrayView2D{indices, {6, 2}, {4, 2}}, + Containers::arrayCast<2, char>(Containers::arrayView(data))); + CORRADE_COMPARE(out.str(), + "MeshTools::removeDuplicatesIndexedInPlace(): second index view dimension is not contiguous\n"); +} + +void RemoveDuplicatesTest::removeDuplicatesIndexedInPlaceErasedWrongIndexSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + char indices[6*3]{}; + Int data[1]{}; + + std::stringstream out; + Error redirectError{&out}; + MeshTools::removeDuplicatesIndexedInPlace( + Containers::StridedArrayView2D{indices, {6, 3}}, + Containers::arrayCast<2, char>(Containers::arrayView(data))); + CORRADE_COMPARE(out.str(), + "MeshTools::removeDuplicatesIndexedInPlace(): expected index type size 1, 2 or 4 but got 3\n"); +} + void RemoveDuplicatesTest::removeDuplicatesFuzzyInPlace() { /* Numbers with distance 1 should be merged, numbers with distance 2 should be kept. Testing both even-odd and odd-even sequence to verify that @@ -284,6 +351,63 @@ void RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceEmptyIndicesVertic CORRADE_COMPARE((MeshTools::removeDuplicatesIndexedInPlace({}, {}, 2)), 0); } +template void RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErased() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + /* Same as above, but with an explicit index buffer */ + T indices[]{3, 2, 0, 1, 2, 3}; + Vector2i data[]{ + {1, 0}, + {2, 1}, + {0, 4}, + {1, 5} + }; + + std::size_t count = MeshTools::removeDuplicatesIndexedInPlace( + Containers::arrayCast<2, char>(Containers::arrayView(indices)), + Containers::stridedArrayView(data), 2); + CORRADE_COMPARE_AS(Containers::arrayView(indices), + Containers::arrayView({1, 1, 0, 0, 1, 1}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(Containers::arrayView(data).prefix(count), + Containers::arrayView({{1, 0}, {0, 4}}), + TestSuite::Compare::Container); +} + +void RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErasedNonContiguous() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + char indices[6*4]{}; + Vector2i data[1]; + + std::stringstream out; + Error redirectError{&out}; + MeshTools::removeDuplicatesIndexedInPlace( + Containers::StridedArrayView2D{indices, {6, 2}, {4, 2}}, + Containers::stridedArrayView(data), 2); + CORRADE_COMPARE(out.str(), + "MeshTools::removeDuplicatesIndexedInPlace(): second index view dimension is not contiguous\n"); +} + +void RemoveDuplicatesTest::removeDuplicatesFuzzyIndexedInPlaceErasedWrongIndexSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + char indices[6*3]{}; + Vector2i data[1]; + + std::stringstream out; + Error redirectError{&out}; + MeshTools::removeDuplicatesIndexedInPlace( + Containers::StridedArrayView2D{indices, {6, 3}}, + Containers::stridedArrayView(data), 2); + CORRADE_COMPARE(out.str(), + "MeshTools::removeDuplicatesIndexedInPlace(): expected index type size 1, 2 or 4 but got 3\n"); +} + }}}} CORRADE_TEST_MAIN(Magnum::MeshTools::Test::RemoveDuplicatesTest)