从数组

时间:2015-12-10 14:00:24

标签: c++ algorithm 3d hashtable

我有一系列积分。每个点都有位置(x,y,z)和法向量(xn,yn,zn),共有6个双精度数。我需要在这个数组中找到唯一的元素,并考虑浮点容差删除重复的条目。

实施它的简单有效方法是什么? 我想过构建一些像BSP或KD-Tree这样的空间划分结构。但我认为应该有更优化的方式,如智能哈希字典或其他东西。

所以我正在寻求建议的方法,是否有任何已经实现它的轻量级C ++库?

2 个答案:

答案 0 :(得分:1)

最简单的事情是舍入到最近的epsilon并将这些点带入整数范围(将所有内容乘以1/epsilon)。一旦它们是整数哈希就可以正常工作(std::unordered_setstd::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;
};