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.
vectorfields
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
*/
#include "AbstractTool.h"
#include <unordered_map>
#include <limits>
#include "TypeTraits.h"
namespace Magnum { namespace MeshTools {
@ -28,10 +31,14 @@ namespace Magnum { namespace MeshTools {
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:
/** @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
@ -39,7 +46,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public Abs
* See clean() for full documentation.
*/
void operator()(typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
if(this->indices.empty()) return;
if(indices.empty()) return;
/* Get mesh bounds */
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();
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)
if((*it)[i] < min[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) {
/* 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;
/* Reserve space for all vertices */
table.reserve(this->vertices.size());
table.reserve(vertices.size());
/* 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 */
size_t index[vertexSize];
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
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 */
std::vector<Vertex> newVertices(table.size());
for(auto it = table.cbegin(); it != table.cend(); ++it)
newVertices[it->second.newIndex] = this->vertices[it->second.oldIndex];
std::swap(newVertices, this->vertices);
newVertices[it->second.newIndex] = vertices[it->second.oldIndex];
std::swap(newVertices, vertices);
/* Move vertex coordinates by epsilon/2 in next direction */
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) {}
};
std::vector<unsigned int>& indices;
std::vector<Vertex>& vertices;
};
/**
@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,
when dealing with perspective in 3D space, only first three fields of
otherwise 4D vertex are important)
@param builder %Mesh builder to operate on
@param epsilon Epsilon value, vertices nearer than this
distance will be melt together.
@param indices Index array to operate on
@param vertices Vertex array to operate on
@param epsilon Epsilon value, vertices nearer than this distance will be
melt together.
Removes duplicate vertices from the mesh.
This is convenience function supplementing direct usage of Clean class,
instead of
@code
MeshBuilder<T> builder;
MeshTools::Clean<T>{builder}(epsilon);
MeshTools::Clean<T>(indices, vertices)(epsilon);
@endcode
you can just write
@code
MeshTools::clean(builder, epsilon);
MeshTools::clean(indices, vertices, epsilon);
@endcode
However, when you want to specify @c vertexSize template parameter, you have
to explicitly specify both of them:
@code
MeshTools::clean<T, 3>(builder, epsilon);
MeshTools::clean<T, 3>(indices, vertices, epsilon);
@endcode
*/
template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(MeshBuilder<Vertex>& builder, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
Clean<Vertex, vertexSize>{builder}(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>(indices, vertices)(epsilon);
}
}}

53
src/MeshTools/Subdivide.h

@ -19,7 +19,7 @@
* @brief Class Magnum::MeshTools::Subdivide
*/
#include "AbstractTool.h"
#include <vector>
namespace Magnum { namespace MeshTools {
@ -28,10 +28,14 @@ namespace Magnum { namespace MeshTools {
See subdivide() for full documentation.
*/
template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<Vertex> {
template<class Vertex, class Interpolator> class Subdivide {
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
@ -39,15 +43,15 @@ template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<
* See subdivide() for full documentation.
*/
void operator()(Interpolator interpolator) {
size_t indexCount = this->indices.size();
this->indices.reserve(this->indices.size()*4);
size_t indexCount = indices.size();
indices.reserve(indices.size()*4);
/* Subdivide each face to four new */
for(size_t i = 0; i != indexCount; i += 3) {
/* Interpolate each side */
unsigned int newVertices[3];
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)
@ -62,20 +66,36 @@ template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<
* / \ / \
* orig 1 ----- new 1 ---- orig 2
*/
this->builder.addFace(this->indices[i], newVertices[0], newVertices[2]);
this->builder.addFace(newVertices[0], this->indices[i+1], newVertices[1]);
this->builder.addFace(newVertices[2], newVertices[1], this->indices[i+2]);
addFace(indices[i], newVertices[0], newVertices[2]);
addFace(newVertices[0], indices[i+1], newVertices[1]);
addFace(newVertices[2], newVertices[1], indices[i+2]);
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
@tparam Vertex Vertex data type (the same as in MeshBuilder)
@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
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,
instead of
@code
MeshBuilder<T> builder;
MeshTools::Subdivide<T, Interpolator>{builder}(interpolator);
MeshTools::Subdivide<T, Interpolator>(indices, vertices)(interpolator);
@endcode
you can just write
@code
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(indices, vertices, interpolator);
@endcode
*/
template<class Vertex, class Interpolator> inline void subdivide(MeshBuilder<Vertex>& builder, Interpolator interpolator) {
Subdivide<Vertex, Interpolator>{builder}(interpolator);
template<class Vertex, class Interpolator> inline void subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, Interpolator 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 {
void CleanTest::cleanMesh() {
MeshBuilder<Vector1> builder;
builder.addVertex(1);
builder.addVertex(2);
builder.addVertex(1);
builder.addVertex(4);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
MeshTools::clean<Vector1, 1>(builder, 1);
vector<Vector1> vertices{1, 2, 1, 4};
vector<unsigned int> indices{0, 1, 2, 1, 2, 3};
MeshTools::clean(indices, vertices);
/* Verify cleanup */
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 0, 1, 0, 2}));
QVERIFY((vertices == vector<Vector1>{1, 2, 4}));
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 "MeshBuilder.h"
#include "MeshTools/Clean.h"
#include "MeshTools/Subdivide.h"
@ -28,24 +27,19 @@ using namespace std;
namespace Magnum { namespace MeshTools { namespace Test {
void SubdivideTest::subdivide() {
MeshBuilder<Vector1> builder;
builder.addVertex(0);
builder.addVertex(2);
builder.addVertex(6);
builder.addVertex(8);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
vector<Vector1> vertices{0, 2, 6, 8};
vector<unsigned int> indices{0, 1, 2, 1, 2, 3};
MeshTools::subdivide(indices, vertices, interpolator);
MeshTools::subdivide(builder, interpolator);
QVERIFY(builder.indices().size() == 24);
QVERIFY(indices.size() == 24);
QVERIFY((builder.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((vertices == vector<Vector1>{0, 2, 6, 8, 1, 4, 3, 4, 7, 5}));
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 */
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,
instead of
@code
MeshBuilder<T> builder;
MeshTools::Tipsify{builder}(cacheSize);
MeshTools::Tipsify(indices, vertexCount)(cacheSize);
@endcode
you can just write
@code
MeshTools::tipsify(builder, cacheSize);
MeshTools::tipsify(indices, vertexCount, cacheSize);
@endcode
*/
inline void tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount, size_t cacheSize) {

Loading…
Cancel
Save