mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
6.0 KiB
157 lines
6.0 KiB
|
13 years ago
|
#ifndef Magnum_MeshTools_RemoveDuplicates_h
|
||
|
|
#define Magnum_MeshTools_RemoveDuplicates_h
|
||
|
15 years ago
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
13 years ago
|
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
copy of this software and associated documentation files (the "Software"),
|
||
|
|
to deal in the Software without restriction, including without limitation
|
||
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
Software is furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included
|
||
|
|
in all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
|
DEALINGS IN THE SOFTWARE.
|
||
|
15 years ago
|
*/
|
||
|
|
|
||
|
|
/** @file
|
||
|
13 years ago
|
* @brief Function Magnum::MeshTools::removeDuplicates()
|
||
|
15 years ago
|
*/
|
||
|
|
|
||
|
14 years ago
|
#include <limits>
|
||
|
13 years ago
|
#include <unordered_map>
|
||
|
|
#include <vector>
|
||
|
14 years ago
|
#include <Utility/MurmurHash2.h>
|
||
|
14 years ago
|
|
||
|
13 years ago
|
#include "Math/Functions.h"
|
||
|
13 years ago
|
#include "Magnum.h"
|
||
|
15 years ago
|
|
||
|
|
namespace Magnum { namespace MeshTools {
|
||
|
|
|
||
|
14 years ago
|
namespace Implementation {
|
||
|
15 years ago
|
|
||
|
13 years ago
|
template<class Vertex, std::size_t vertexSize = Vertex::Size> class RemoveDuplicates {
|
||
|
15 years ago
|
public:
|
||
|
13 years ago
|
RemoveDuplicates(std::vector<UnsignedInt>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {}
|
||
|
15 years ago
|
|
||
|
13 years ago
|
void operator()(typename Vertex::Type epsilon = Math::TypeTraits<typename Vertex::Type>::epsilon());
|
||
|
15 years ago
|
|
||
|
|
private:
|
||
|
|
class IndexHash {
|
||
|
|
public:
|
||
|
13 years ago
|
std::size_t operator()(const Math::Vector<vertexSize, std::size_t>& data) const {
|
||
|
13 years ago
|
return *reinterpret_cast<const std::size_t*>(Utility::MurmurHash2()(reinterpret_cast<const char*>(&data), sizeof(data)).byteArray());
|
||
|
15 years ago
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct HashedVertex {
|
||
|
13 years ago
|
UnsignedInt oldIndex, newIndex;
|
||
|
15 years ago
|
|
||
|
13 years ago
|
HashedVertex(UnsignedInt oldIndex, UnsignedInt newIndex): oldIndex(oldIndex), newIndex(newIndex) {}
|
||
|
15 years ago
|
};
|
||
|
14 years ago
|
|
||
|
13 years ago
|
std::vector<UnsignedInt>& indices;
|
||
|
14 years ago
|
std::vector<Vertex>& vertices;
|
||
|
15 years ago
|
};
|
||
|
|
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
13 years ago
|
@brief %Remove duplicate vertices from the mesh
|
||
|
14 years ago
|
@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[in,out] indices Index array to operate on
|
||
|
|
@param[in,out] vertices Vertex array to operate on
|
||
|
|
@param[in] epsilon Epsilon value, vertices nearer than this distance will
|
||
|
|
be melt together.
|
||
|
15 years ago
|
|
||
|
|
Removes duplicate vertices from the mesh.
|
||
|
13 years ago
|
@see duplicate()
|
||
|
14 years ago
|
|
||
|
|
@todo Different (no cycle) implementation for integral vertices
|
||
|
|
@todo Interpolate vertices, not collapse them to first in the cell
|
||
|
|
@todo Ability to specify other attributes for interpolation
|
||
|
15 years ago
|
*/
|
||
|
13 years ago
|
template<class Vertex, std::size_t vertexSize = Vertex::Size> inline void removeDuplicates(std::vector<UnsignedInt>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = Math::TypeTraits<typename Vertex::Type>::epsilon()) {
|
||
|
|
Implementation::RemoveDuplicates<Vertex, vertexSize>(indices, vertices)(epsilon);
|
||
|
15 years ago
|
}
|
||
|
|
|
||
|
13 years ago
|
namespace Implementation {
|
||
|
|
|
||
|
13 years ago
|
template<class Vertex, std::size_t vertexSize> void RemoveDuplicates<Vertex, vertexSize>::operator()(typename Vertex::Type epsilon) {
|
||
|
13 years ago
|
if(indices.empty()) return;
|
||
|
|
|
||
|
|
/* Get mesh bounds */
|
||
|
13 years ago
|
Vertex min = vertices[0], max = vertices[0];
|
||
|
|
for(const auto& v: vertices) {
|
||
|
|
min = Math::min(v, min);
|
||
|
|
max = Math::max(v, max);
|
||
|
13 years ago
|
}
|
||
|
13 years ago
|
|
||
|
|
/* Make epsilon so large that std::size_t can index all vertices inside
|
||
|
|
mesh bounds. */
|
||
|
|
epsilon = Math::max(epsilon, static_cast<typename Vertex::Type>((max-min).max()/std::numeric_limits<std::size_t>::max()));
|
||
|
13 years ago
|
|
||
|
|
/* First go with original vertex coordinates, then move them by
|
||
|
13 years ago
|
epsilon/2 in each direction. */
|
||
|
13 years ago
|
Vertex moved;
|
||
|
|
for(std::size_t moving = 0; moving <= vertexSize; ++moving) {
|
||
|
|
|
||
|
|
/* Under each index is pointer to face which contains given vertex
|
||
|
13 years ago
|
and index of vertex in the face. */
|
||
|
13 years ago
|
std::unordered_map<Math::Vector<vertexSize, std::size_t>, HashedVertex, IndexHash> table;
|
||
|
|
|
||
|
|
/* Reserve space for all vertices */
|
||
|
|
table.reserve(vertices.size());
|
||
|
|
|
||
|
|
/* Go through all faces' vertices */
|
||
|
|
for(auto it = indices.begin(); it != indices.end(); ++it) {
|
||
|
|
/* Index of a vertex in vertexSize-dimensional table */
|
||
|
|
std::size_t index[vertexSize];
|
||
|
|
for(std::size_t ii = 0; ii != vertexSize; ++ii)
|
||
|
13 years ago
|
index[ii] = std::size_t((vertices[*it][ii]+moved[ii]-min[ii])/epsilon);
|
||
|
13 years ago
|
|
||
|
|
/* Try inserting the vertex into table, if it already
|
||
|
13 years ago
|
exists, change vertex pointer of the face to already
|
||
|
|
existing vertex */
|
||
|
13 years ago
|
HashedVertex v(*it, table.size());
|
||
|
13 years ago
|
#ifndef CORRADE_GCC46_COMPATIBILITY
|
||
|
13 years ago
|
auto result = table.emplace(Math::Vector<vertexSize, std::size_t>::from(index), v);
|
||
|
13 years ago
|
#else
|
||
|
|
auto result = table.insert({Math::Vector<vertexSize, std::size_t>::from(index), v});
|
||
|
|
#endif
|
||
|
13 years ago
|
*it = result.first->second.newIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Shrink vertices array */
|
||
|
|
std::vector<Vertex> newVertices(table.size());
|
||
|
|
for(auto it = table.cbegin(); it != table.cend(); ++it)
|
||
|
|
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) {
|
||
|
|
moved = Vertex();
|
||
|
|
moved[moving] = epsilon/2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
}}
|
||
|
|
|
||
|
|
#endif
|