#pragma once
#include <array>
#include <deque>
#include <vector>
#include "./shared.h"
#include "./vec.h"
namespace manifold {
class Pool {
std::vector<std::unique_ptr<Vec<size_t>>> data;
public:
void clear() { data.clear(); }
void reclaim(std::unique_ptr<Vec<size_t>>& ptr) {
data.push_back(std::move(ptr));
}
std::unique_ptr<Vec<size_t>> get() {
if (data.size() == 0) {
return std::make_unique<Vec<size_t>>();
}
auto it = data.end() - 1;
std::unique_ptr<Vec<size_t>> r = std::move(*it);
data.erase(it);
return r;
}
};
class Plane {
public:
vec3 N;
double D;
double sqrNLength;
bool isPointOnPositiveSide(const vec3& Q) const {
double d = la::dot(N, Q) + D;
if (d >= 0) return true;
return false;
}
Plane() = default;
Plane(const vec3& N, const vec3& P)
: N(N), D(la::dot(-N, P)), sqrNLength(la::dot(N, N)) {}
};
struct Ray {
const vec3 S;
const vec3 V;
const double VInvLengthSquared;
Ray(const vec3& S, const vec3& V)
: S(S), V(V), VInvLengthSquared(1 / (la::dot(V, V))) {}
};
class MeshBuilder {
public:
struct Face {
int he;
Plane P{};
double mostDistantPointDist = 0.0;
size_t mostDistantPoint = 0;
size_t visibilityCheckedOnIteration = 0;
std::uint8_t isVisibleFaceOnCurrentIteration : 1;
std::uint8_t inFaceStack : 1;
std::uint8_t horizonEdgesOnCurrentIteration : 3;
std::unique_ptr<Vec<size_t>> pointsOnPositiveSide;
Face(size_t he)
: he(he),
isVisibleFaceOnCurrentIteration(0),
inFaceStack(0),
horizonEdgesOnCurrentIteration(0) {}
Face()
: he(-1),
isVisibleFaceOnCurrentIteration(0),
inFaceStack(0),
horizonEdgesOnCurrentIteration(0) {}
void disable() { he = -1; }
bool isDisabled() const { return he == -1; }
};
std::vector<Face> faces;
Vec<Halfedge> halfedges;
Vec<int> halfedgeToFace;
Vec<int> halfedgeNext;
Vec<size_t> disabledFaces, disabledHalfedges;
size_t addFace();
size_t addHalfedge();
std::unique_ptr<Vec<size_t>> disableFace(size_t faceIndex) {
auto& f = faces[faceIndex];
f.disable();
disabledFaces.push_back(faceIndex);
return std::move(f.pointsOnPositiveSide);
}
void disableHalfedge(size_t heIndex) {
auto& he = halfedges[heIndex];
he.pairedHalfedge = -1;
disabledHalfedges.push_back(heIndex);
}
MeshBuilder() = default;
void setup(int a, int b, int c, int d);
std::array<int, 3> getVertexIndicesOfFace(const Face& f) const;
std::array<int, 2> getVertexIndicesOfHalfEdge(const Halfedge& he) const {
return {halfedges[he.pairedHalfedge].endVert, he.endVert};
}
std::array<int, 3> getHalfEdgeIndicesOfFace(const Face& f) const {
return {f.he, halfedgeNext[f.he], halfedgeNext[halfedgeNext[f.he]]};
}
};
class HalfEdgeMesh {
public:
Vec<vec3> vertices;
std::vector<size_t> halfEdgeIndexFaces;
Vec<Halfedge> halfedges;
Vec<int> halfedgeToFace;
Vec<int> halfedgeNext;
HalfEdgeMesh(const MeshBuilder& builderObject,
const VecView<vec3>& vertexData);
};
double defaultEps();
class QuickHull {
struct FaceData {
int faceIndex;
int enteredFromHalfedge;
};
double m_epsilon, epsilonSquared, scale;
bool planar;
Vec<vec3> planarPointCloudTemp;
VecView<vec3> originalVertexData;
MeshBuilder mesh;
std::array<size_t, 6> extremeValues;
size_t failedHorizonEdges = 0;
Vec<size_t> newFaceIndices;
Vec<size_t> newHalfedgeIndices;
Vec<size_t> visibleFaces;
Vec<size_t> horizonEdgesData;
Vec<FaceData> possiblyVisibleFaces;
std::vector<std::unique_ptr<Vec<size_t>>> disabledFacePointVectors;
std::deque<int> faceList;
void setupInitialTetrahedron();
bool reorderHorizonEdges(VecView<size_t>& horizonEdges);
std::array<size_t, 6> getExtremeValues();
double getScale(const std::array<size_t, 6>& extremeValuesInput);
Pool indexVectorPool;
inline std::unique_ptr<Vec<size_t>> getIndexVectorFromPool();
inline void reclaimToIndexVectorPool(std::unique_ptr<Vec<size_t>>& ptr);
inline bool addPointToFace(typename MeshBuilder::Face& f, size_t pointIndex);
void createConvexHalfedgeMesh();
public:
QuickHull(VecView<vec3> pointCloudVec)
: originalVertexData(VecView(pointCloudVec)) {}
std::pair<Vec<Halfedge>, Vec<vec3>> buildMesh(double eps = defaultEps());
};
}