Browse Source

MeshTools: removed dependency on MeshBuilder in Clean and Subdivide.

SubdivideCleanBenchmark and Primitives library currently doesn't
compile, will be fixed in next commits.
pull/279/head
Vladimír Vondruš 14 years ago
parent
commit
02b71d6b15
  1. 54
      src/MeshTools/Clean.h
  2. 53
      src/MeshTools/Subdivide.h
  3. 16
      src/MeshTools/Test/CleanTest.cpp
  4. 22
      src/MeshTools/Test/SubdivideTest.cpp
  5. 5
      src/MeshTools/Tipsify.h

54
src/MeshTools/Clean.h

@ -19,7 +19,10 @@
* @brief Class Magnum::MeshTools::Clean * @brief Class Magnum::MeshTools::Clean
*/ */
#include "AbstractTool.h" #include <unordered_map>
#include <limits>
#include "TypeTraits.h"
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
@ -28,10 +31,14 @@ namespace Magnum { namespace MeshTools {
See clean() for full documentation. See clean() for full documentation.
*/ */
template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public AbstractTool<Vertex> { template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
public: public:
/** @copydoc AbstractTool::AbstractTool() */ /**
inline Clean(MeshBuilder<Vertex>& builder): AbstractTool<Vertex>(builder) {} * @brief Constructor
*
* See clean() for full documentation.
*/
inline Clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {}
/** /**
* @brief Functor * @brief Functor
@ -39,7 +46,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
* See clean() for full documentation. * See clean() for full documentation.
*/ */
void operator()(typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) { void operator()(typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
if(this->indices.empty()) return; if(indices.empty()) return;
/* Get mesh bounds */ /* Get mesh bounds */
Vertex min, max; Vertex min, max;
@ -47,7 +54,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
min[i] = std::numeric_limits<typename Vertex::Type>::max(); min[i] = std::numeric_limits<typename Vertex::Type>::max();
max[i] = std::numeric_limits<typename Vertex::Type>::min(); max[i] = std::numeric_limits<typename Vertex::Type>::min();
} }
for(auto it = this->vertices.cbegin(); it != this->vertices.cend(); ++it) for(auto it = vertices.cbegin(); it != vertices.cend(); ++it)
for(size_t i = 0; i != vertexSize; ++i) for(size_t i = 0; i != vertexSize; ++i)
if((*it)[i] < min[i]) if((*it)[i] < min[i])
min[i] = (*it)[i]; min[i] = (*it)[i];
@ -67,18 +74,18 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
for(size_t moving = 0; moving <= vertexSize; ++moving) { for(size_t moving = 0; moving <= vertexSize; ++moving) {
/* Under each index is pointer to face which contains given vertex /* Under each index is pointer to face which contains given vertex
and index of vertex in the face. */ and index of vertex in the face. */
std::unordered_map<Math::Vector<size_t, vertexSize>, HashedVertex, IndexHash> table; std::unordered_map<Math::Vector<size_t, vertexSize>, HashedVertex, IndexHash> table;
/* Reserve space for all vertices */ /* Reserve space for all vertices */
table.reserve(this->vertices.size()); table.reserve(vertices.size());
/* Go through all faces' vertices */ /* Go through all faces' vertices */
for(auto it = this->indices.begin(); it != this->indices.end(); ++it) { for(auto it = indices.begin(); it != indices.end(); ++it) {
/* Index of a vertex in vertexSize-dimensional table */ /* Index of a vertex in vertexSize-dimensional table */
size_t index[vertexSize]; size_t index[vertexSize];
for(size_t ii = 0; ii != vertexSize; ++ii) for(size_t ii = 0; ii != vertexSize; ++ii)
index[ii] = (this->vertices[*it][ii]+moved[ii]-min[ii])/epsilon; index[ii] = (vertices[*it][ii]+moved[ii]-min[ii])/epsilon;
/* Try inserting the vertex into table, if it already /* Try inserting the vertex into table, if it already
exists, change vertex pointer of the face to already exists, change vertex pointer of the face to already
@ -91,8 +98,8 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
/* Shrink vertices array */ /* Shrink vertices array */
std::vector<Vertex> newVertices(table.size()); std::vector<Vertex> newVertices(table.size());
for(auto it = table.cbegin(); it != table.cend(); ++it) for(auto it = table.cbegin(); it != table.cend(); ++it)
newVertices[it->second.newIndex] = this->vertices[it->second.oldIndex]; newVertices[it->second.newIndex] = vertices[it->second.oldIndex];
std::swap(newVertices, this->vertices); std::swap(newVertices, vertices);
/* Move vertex coordinates by epsilon/2 in next direction */ /* Move vertex coordinates by epsilon/2 in next direction */
if(moving != Vertex::Size) { if(moving != Vertex::Size) {
@ -118,38 +125,41 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
HashedVertex(unsigned int oldIndex, unsigned int newIndex): oldIndex(oldIndex), newIndex(newIndex) {} HashedVertex(unsigned int oldIndex, unsigned int newIndex): oldIndex(oldIndex), newIndex(newIndex) {}
}; };
std::vector<unsigned int>& indices;
std::vector<Vertex>& vertices;
}; };
/** /**
@brief %Clean the mesh @brief %Clean the mesh
@tparam Vertex Vertex data type (the same as in MeshBuilder) @tparam Vertex Vertex data type
@tparam vertexSize How many initial vertex fields are important (for example, @tparam vertexSize How many initial vertex fields are important (for example,
when dealing with perspective in 3D space, only first three fields of when dealing with perspective in 3D space, only first three fields of
otherwise 4D vertex are important) otherwise 4D vertex are important)
@param builder %Mesh builder to operate on @param indices Index array to operate on
@param epsilon Epsilon value, vertices nearer than this @param vertices Vertex array to operate on
distance will be melt together. @param epsilon Epsilon value, vertices nearer than this distance will be
melt together.
Removes duplicate vertices from the mesh. Removes duplicate vertices from the mesh.
This is convenience function supplementing direct usage of Clean class, This is convenience function supplementing direct usage of Clean class,
instead of instead of
@code @code
MeshBuilder<T> builder; MeshTools::Clean<T>(indices, vertices)(epsilon);
MeshTools::Clean<T>{builder}(epsilon);
@endcode @endcode
you can just write you can just write
@code @code
MeshTools::clean(builder, epsilon); MeshTools::clean(indices, vertices, epsilon);
@endcode @endcode
However, when you want to specify @c vertexSize template parameter, you have However, when you want to specify @c vertexSize template parameter, you have
to explicitly specify both of them: to explicitly specify both of them:
@code @code
MeshTools::clean<T, 3>(builder, epsilon); MeshTools::clean<T, 3>(indices, vertices, epsilon);
@endcode @endcode
*/ */
template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(MeshBuilder<Vertex>& builder, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) { template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
Clean<Vertex, vertexSize>{builder}(epsilon); Clean<Vertex, vertexSize>(indices, vertices)(epsilon);
} }
}} }}

53
src/MeshTools/Subdivide.h

@ -19,7 +19,7 @@
* @brief Class Magnum::MeshTools::Subdivide * @brief Class Magnum::MeshTools::Subdivide
*/ */
#include "AbstractTool.h" #include <vector>
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
@ -28,10 +28,14 @@ namespace Magnum { namespace MeshTools {
See subdivide() for full documentation. See subdivide() for full documentation.
*/ */
template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<Vertex> { template<class Vertex, class Interpolator> class Subdivide {
public: public:
/** @copydoc AbstractTool::AbstractTool() */ /**
inline Subdivide(MeshBuilder<Vertex>& builder): AbstractTool<Vertex>(builder) {} * @brief Constructor
*
* See subdivide() for full documentation.
*/
inline Subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {}
/** /**
* @brief Functor * @brief Functor
@ -39,15 +43,15 @@ template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<
* See subdivide() for full documentation. * See subdivide() for full documentation.
*/ */
void operator()(Interpolator interpolator) { void operator()(Interpolator interpolator) {
size_t indexCount = this->indices.size(); size_t indexCount = indices.size();
this->indices.reserve(this->indices.size()*4); indices.reserve(indices.size()*4);
/* Subdivide each face to four new */ /* Subdivide each face to four new */
for(size_t i = 0; i != indexCount; i += 3) { for(size_t i = 0; i != indexCount; i += 3) {
/* Interpolate each side */ /* Interpolate each side */
unsigned int newVertices[3]; unsigned int newVertices[3];
for(int j = 0; j != 3; ++j) for(int j = 0; j != 3; ++j)
newVertices[j] = this->builder.addVertex(interpolator(this->vertices[this->indices[i+j]], this->vertices[this->indices[i+(j+1)%3]])); newVertices[j] = addVertex(interpolator(vertices[indices[i+j]], vertices[indices[i+(j+1)%3]]));
/* /*
* Add three new faces (0, 1, 3) and update original (2) * Add three new faces (0, 1, 3) and update original (2)
@ -62,20 +66,36 @@ template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<
* / \ / \ * / \ / \
* orig 1 ----- new 1 ---- orig 2 * orig 1 ----- new 1 ---- orig 2
*/ */
this->builder.addFace(this->indices[i], newVertices[0], newVertices[2]); addFace(indices[i], newVertices[0], newVertices[2]);
this->builder.addFace(newVertices[0], this->indices[i+1], newVertices[1]); addFace(newVertices[0], indices[i+1], newVertices[1]);
this->builder.addFace(newVertices[2], newVertices[1], this->indices[i+2]); addFace(newVertices[2], newVertices[1], indices[i+2]);
for(size_t j = 0; j != 3; ++j) for(size_t j = 0; j != 3; ++j)
this->indices[i+j] = newVertices[j]; indices[i+j] = newVertices[j];
} }
} }
private:
std::vector<unsigned int>& indices;
std::vector<Vertex>& vertices;
unsigned int addVertex(const Vertex& v) {
vertices.push_back(v);
return vertices.size()-1;
}
void addFace(unsigned int first, unsigned int second, unsigned int third) {
indices.push_back(first);
indices.push_back(second);
indices.push_back(third);
}
}; };
/** /**
@brief %Subdivide the mesh @brief %Subdivide the mesh
@tparam Vertex Vertex data type (the same as in MeshBuilder) @tparam Vertex Vertex data type (the same as in MeshBuilder)
@tparam Interpolator See @c interpolator function parameter @tparam Interpolator See @c interpolator function parameter
@param builder %Mesh builder to operate on @param indices Index array to operate on
@param vertices Vertex array to operate on
@param interpolator Functor or function pointer which interpolates @param interpolator Functor or function pointer which interpolates
two adjacent vertices: <tt>Vertex interpolator(Vertex a, Vertex b)</tt> two adjacent vertices: <tt>Vertex interpolator(Vertex a, Vertex b)</tt>
@ -85,16 +105,15 @@ duplicate vertices in the mesh is up to user.
This is convenience function supplementing direct usage of Subdivide class, This is convenience function supplementing direct usage of Subdivide class,
instead of instead of
@code @code
MeshBuilder<T> builder; MeshTools::Subdivide<T, Interpolator>(indices, vertices)(interpolator);
MeshTools::Subdivide<T, Interpolator>{builder}(interpolator);
@endcode @endcode
you can just write you can just write
@code @code
MeshTools::subdivide(builder, interpolator); MeshTools::subdivide(indices, vertices, interpolator);
@endcode @endcode
*/ */
template<class Vertex, class Interpolator> inline void subdivide(MeshBuilder<Vertex>& builder, Interpolator interpolator) { template<class Vertex, class Interpolator> inline void subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, Interpolator interpolator) {
Subdivide<Vertex, Interpolator>{builder}(interpolator); Subdivide<Vertex, Interpolator>(indices, vertices)(interpolator);
} }
}} }}

16
src/MeshTools/Test/CleanTest.cpp

@ -26,19 +26,13 @@ using namespace std;
namespace Magnum { namespace MeshTools { namespace Test { namespace Magnum { namespace MeshTools { namespace Test {
void CleanTest::cleanMesh() { void CleanTest::cleanMesh() {
MeshBuilder<Vector1> builder; vector<Vector1> vertices{1, 2, 1, 4};
builder.addVertex(1); vector<unsigned int> indices{0, 1, 2, 1, 2, 3};
builder.addVertex(2); MeshTools::clean(indices, vertices);
builder.addVertex(1);
builder.addVertex(4);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
MeshTools::clean<Vector1, 1>(builder, 1);
/* Verify cleanup */ /* Verify cleanup */
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 4})); QVERIFY((vertices == vector<Vector1>{1, 2, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 0, 1, 0, 2})); QVERIFY((indices == vector<unsigned int>{0, 1, 0, 1, 0, 2}));
} }
}}} }}}

22
src/MeshTools/Test/SubdivideTest.cpp

@ -17,7 +17,6 @@
#include <QtTest/QTest> #include <QtTest/QTest>
#include "MeshBuilder.h"
#include "MeshTools/Clean.h" #include "MeshTools/Clean.h"
#include "MeshTools/Subdivide.h" #include "MeshTools/Subdivide.h"
@ -28,24 +27,19 @@ using namespace std;
namespace Magnum { namespace MeshTools { namespace Test { namespace Magnum { namespace MeshTools { namespace Test {
void SubdivideTest::subdivide() { void SubdivideTest::subdivide() {
MeshBuilder<Vector1> builder; vector<Vector1> vertices{0, 2, 6, 8};
builder.addVertex(0); vector<unsigned int> indices{0, 1, 2, 1, 2, 3};
builder.addVertex(2); MeshTools::subdivide(indices, vertices, interpolator);
builder.addVertex(6);
builder.addVertex(8);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
MeshTools::subdivide(builder, interpolator); QVERIFY(indices.size() == 24);
QVERIFY(builder.indices().size() == 24);
QVERIFY((builder.vertices() == vector<Vector1>{0, 2, 6, 8, 1, 4, 3, 4, 7, 5})); QVERIFY((vertices == vector<Vector1>{0, 2, 6, 8, 1, 4, 3, 4, 7, 5}));
QVERIFY((builder.indices() == vector<unsigned int>{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3})); QVERIFY((indices == vector<unsigned int>{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3}));
MeshTools::clean(builder, 1); MeshTools::clean(indices, vertices);
/* Vertices 0, 1, 2, 3, 4, 5, 6, 7, 8 */ /* Vertices 0, 1, 2, 3, 4, 5, 6, 7, 8 */
QVERIFY(builder.vertices().size() == 9); QVERIFY(vertices.size() == 9);
} }
}}} }}}

5
src/MeshTools/Tipsify.h

@ -76,12 +76,11 @@ Triangle Reordering for Vertex Locality and Reduced Overdraw</a>, SIGGRAPH
This is convenience function supplementing direct usage of Tipsify class, This is convenience function supplementing direct usage of Tipsify class,
instead of instead of
@code @code
MeshBuilder<T> builder; MeshTools::Tipsify(indices, vertexCount)(cacheSize);
MeshTools::Tipsify{builder}(cacheSize);
@endcode @endcode
you can just write you can just write
@code @code
MeshTools::tipsify(builder, cacheSize); MeshTools::tipsify(indices, vertexCount, cacheSize);
@endcode @endcode
*/ */
inline void tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount, size_t cacheSize) { inline void tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount, size_t cacheSize) {

Loading…
Cancel
Save