netradiant-custom/libs/quickhull/Structs/Mesh.hpp
2023-05-16 13:54:27 +06:00

255 lines
5.7 KiB
C++

#ifndef MESH_HPP_
#define MESH_HPP_
#include <vector>
#include "Vector3.hpp"
#include "Plane.hpp"
#include "Pool.hpp"
#include <array>
#include <cassert>
#include <limits>
#include <memory>
#include "VertexDataSource.hpp"
#include <unordered_map>
namespace quickhull {
template <typename T>
class MeshBuilder {
public:
struct HalfEdge {
size_t m_endVertex;
size_t m_opp;
size_t m_face;
size_t m_next;
void disable() {
m_endVertex = std::numeric_limits<size_t>::max();
}
bool isDisabled() const {
return m_endVertex == std::numeric_limits<size_t>::max();
}
};
struct Face {
size_t m_he;
Plane<T> m_P;
T m_mostDistantPointDist;
size_t m_mostDistantPoint;
size_t m_visibilityCheckedOnIteration;
std::uint8_t m_isVisibleFaceOnCurrentIteration : 1;
std::uint8_t m_inFaceStack : 1;
std::uint8_t m_horizonEdgesOnCurrentIteration : 3; // Bit for each half edge assigned to this face, each being 0 or 1 depending on whether the edge belongs to horizon edge
std::unique_ptr<std::vector<size_t>> m_pointsOnPositiveSide;
Face() : m_he(std::numeric_limits<size_t>::max()),
m_mostDistantPointDist(0),
m_mostDistantPoint(0),
m_visibilityCheckedOnIteration(0),
m_isVisibleFaceOnCurrentIteration(0),
m_inFaceStack(0),
m_horizonEdgesOnCurrentIteration(0)
{
}
void disable() {
m_he = std::numeric_limits<size_t>::max();
}
bool isDisabled() const {
return m_he == std::numeric_limits<size_t>::max();
}
};
// Mesh data
std::vector<Face> m_faces;
std::vector<HalfEdge> m_halfEdges;
// When the mesh is modified and faces and half edges are removed from it, we do not actually remove them from the container vectors.
// Insted, they are marked as disabled which means that the indices can be reused when we need to add new faces and half edges to the mesh.
// We store the free indices in the following vectors.
std::vector<size_t> m_disabledFaces,m_disabledHalfEdges;
size_t addFace() {
if (m_disabledFaces.size()) {
size_t index = m_disabledFaces.back();
auto& f = m_faces[index];
assert(f.isDisabled());
assert(!f.m_pointsOnPositiveSide);
f.m_mostDistantPointDist = 0;
m_disabledFaces.pop_back();
return index;
}
m_faces.emplace_back();
return m_faces.size()-1;
}
size_t addHalfEdge() {
if (m_disabledHalfEdges.size()) {
const size_t index = m_disabledHalfEdges.back();
m_disabledHalfEdges.pop_back();
return index;
}
m_halfEdges.emplace_back();
return m_halfEdges.size()-1;
}
// Mark a face as disabled and return a pointer to the points that were on the positive of it.
std::unique_ptr<std::vector<size_t>> disableFace(size_t faceIndex) {
auto& f = m_faces[faceIndex];
f.disable();
m_disabledFaces.push_back(faceIndex);
return std::move(f.m_pointsOnPositiveSide);
}
void disableHalfEdge(size_t heIndex) {
auto& he = m_halfEdges[heIndex];
he.disable();
m_disabledHalfEdges.push_back(heIndex);
}
MeshBuilder() = default;
// Create a mesh with initial tetrahedron ABCD. Dot product of AB with the normal of triangle ABC should be negative.
void setup(size_t a, size_t b, size_t c, size_t d) {
m_faces.clear();
m_halfEdges.clear();
m_disabledFaces.clear();
m_disabledHalfEdges.clear();
m_faces.reserve(4);
m_halfEdges.reserve(12);
// Create halfedges
HalfEdge AB;
AB.m_endVertex = b;
AB.m_opp = 6;
AB.m_face = 0;
AB.m_next = 1;
m_halfEdges.push_back(AB);
HalfEdge BC;
BC.m_endVertex = c;
BC.m_opp = 9;
BC.m_face = 0;
BC.m_next = 2;
m_halfEdges.push_back(BC);
HalfEdge CA;
CA.m_endVertex = a;
CA.m_opp = 3;
CA.m_face = 0;
CA.m_next = 0;
m_halfEdges.push_back(CA);
HalfEdge AC;
AC.m_endVertex = c;
AC.m_opp = 2;
AC.m_face = 1;
AC.m_next = 4;
m_halfEdges.push_back(AC);
HalfEdge CD;
CD.m_endVertex = d;
CD.m_opp = 11;
CD.m_face = 1;
CD.m_next = 5;
m_halfEdges.push_back(CD);
HalfEdge DA;
DA.m_endVertex = a;
DA.m_opp = 7;
DA.m_face = 1;
DA.m_next = 3;
m_halfEdges.push_back(DA);
HalfEdge BA;
BA.m_endVertex = a;
BA.m_opp = 0;
BA.m_face = 2;
BA.m_next = 7;
m_halfEdges.push_back(BA);
HalfEdge AD;
AD.m_endVertex = d;
AD.m_opp = 5;
AD.m_face = 2;
AD.m_next = 8;
m_halfEdges.push_back(AD);
HalfEdge DB;
DB.m_endVertex = b;
DB.m_opp = 10;
DB.m_face = 2;
DB.m_next = 6;
m_halfEdges.push_back(DB);
HalfEdge CB;
CB.m_endVertex = b;
CB.m_opp = 1;
CB.m_face = 3;
CB.m_next = 10;
m_halfEdges.push_back(CB);
HalfEdge BD;
BD.m_endVertex = d;
BD.m_opp = 8;
BD.m_face = 3;
BD.m_next = 11;
m_halfEdges.push_back(BD);
HalfEdge DC;
DC.m_endVertex = c;
DC.m_opp = 4;
DC.m_face = 3;
DC.m_next = 9;
m_halfEdges.push_back(DC);
// Create faces
Face ABC;
ABC.m_he = 0;
m_faces.push_back(std::move(ABC));
Face ACD;
ACD.m_he = 3;
m_faces.push_back(std::move(ACD));
Face BAD;
BAD.m_he = 6;
m_faces.push_back(std::move(BAD));
Face CBD;
CBD.m_he = 9;
m_faces.push_back(std::move(CBD));
}
std::array<size_t,3> getVertexIndicesOfFace(const Face& f) const {
std::array<size_t,3> v;
const HalfEdge* he = &m_halfEdges[f.m_he];
v[0] = he->m_endVertex;
he = &m_halfEdges[he->m_next];
v[1] = he->m_endVertex;
he = &m_halfEdges[he->m_next];
v[2] = he->m_endVertex;
return v;
}
std::array<size_t,2> getVertexIndicesOfHalfEdge(const HalfEdge& he) const {
return {m_halfEdges[he.m_opp].m_endVertex,he.m_endVertex};
}
std::array<size_t,3> getHalfEdgeIndicesOfFace(const Face& f) const {
return {f.m_he,m_halfEdges[f.m_he].m_next,m_halfEdges[m_halfEdges[f.m_he].m_next].m_next};
}
};
}
#endif