我有一系列积分。每个点都有位置(x,y,z)和法向量(xn,yn,zn),共有6个双精度数。我需要在这个数组中找到唯一的元素,并考虑浮点容差删除重复的条目。
实施它的简单有效方法是什么? 我想过构建一些像BSP或KD-Tree这样的空间划分结构。但我认为应该有更优化的方式,如智能哈希字典或其他东西。
所以我正在寻求建议的方法,是否有任何已经实现它的轻量级C ++库?
答案 0 :(得分:1)
最简单的事情是舍入到最近的epsilon并将这些点带入整数范围(将所有内容乘以1/epsilon
)。一旦它们是整数哈希就可以正常工作(std::unordered_set
,std::unordered_map
)。这可能会遗漏一些情况,其中2点接近,但它们的轮次不同。您可以通过舍入两种方式并考虑与任一结果的碰撞来克服这一点。
如果您使用std::set
/ std::map
,请注意它们具有日志(N)访问复杂性(与哈希版本的常量相比)。在这一点上,你使用BSP或KD-Tree同样很好(只要你已经有一些库已经实现它们)。
答案 1 :(得分:1)
我的实施:
class VertexMap {
public:
VertexMap(double tolerance): m_tolerance(tolerance), m_invTolerance(1 / tolerance), m_offset(m_tolerance * 0.1) {
m_offset = m_tolerance * 0.1;
m_offset2 = m_offset * 2.0;
}
void add(const MbFloatPoint3D &pos, const MbFloatVector3D &normal, const MbFloatPoint &texture, size_t index) {
m_vertices.emplace(pos, normal, texture, index, m_invTolerance);
}
size_t findIndex(const MbFloatPoint3D &pos, const MbFloatVector3D &normal, const MbFloatPoint &texture) {
auto vertex = Vertex(pos, normal, texture, 0, m_invTolerance);
auto it = m_vertices.find(vertex);
auto itEnd = m_vertices.end();
if (it == itEnd) {
vertex.pos.x -= m_offset;
vertex.pos.y -= m_offset;
vertex.pos.z -= m_offset;
it = m_vertices.find(vertex); // (---)
if (it == itEnd) {
vertex.pos.x += m_offset2;
it = m_vertices.find(vertex); // (+--)
if (it != itEnd) {
vertex.pos.y += m_offset2;
it = m_vertices.find(vertex); // (++-)
if (it != itEnd) {
vertex.pos.x -= m_offset2;
it = m_vertices.find(vertex); // (-+-)
if (it != itEnd) {
vertex.pos.z += m_offset2;
it = m_vertices.find(vertex); // (-++)
if (it != itEnd) {
vertex.pos.y -= m_offset2;
it = m_vertices.find(vertex); // (--+)
if (it != itEnd) {
vertex.pos.x += m_offset2;
it = m_vertices.find(vertex); // (+-+)
if (it != itEnd) {
vertex.pos.y += m_offset2;
it = m_vertices.find(vertex); // (+++)
}
}
}
}
}
}
}
}
if (it != itEnd)
return it->index;
else
return SIZE_MAX;
}
private:
class Vertex {
public:
Vertex(const MbFloatPoint3D &pos, const MbFloatVector3D &normal, const MbFloatPoint &texture, size_t index, double invTolerance):
pos(pos), normal(normal),texture(texture), index(index) {
normalizedx = pos.x * invTolerance;
normalizedy = pos.y * invTolerance;
normalizedz = pos.z * invTolerance;
}
MbFloatPoint3D pos;
MbFloatVector3D normal;
MbFloatPoint texture;
size_t index;
int64_t normalizedx;
int64_t normalizedy;
int64_t normalizedz;
bool operator==(const Vertex &other) const {
return Equalsd(pos, other.pos) && Equalsd(normal, other.normal) && Equalsd(texture, other.texture);
}
};
struct VertexHasher
{
size_t operator()(const Vertex& k) const
{
size_t h1 = std::hash<int64_t>()(k.normalizedx);
size_t h2 = std::hash<int64_t>()(k.normalizedy);
size_t h3 = std::hash<int64_t>()(k.normalizedz);
return (h1 ^ (h2 << 1)) ^ h3;
}
};
double m_tolerance;
double m_invTolerance;
double m_offset;
double m_offset2;
std::unordered_set<Vertex, VertexHasher> m_vertices;
};