dust3d/thirdparty/nodemesh/nodemesh/builder.h

159 lines
5.6 KiB
C++

#ifndef NODEMESH_BUILDER_H
#define NODEMESH_BUILDER_H
#include <QVector3D>
#include <QVector2D>
#include <vector>
#include <map>
#include <set>
#include <QMatrix4x4>
namespace nodemesh
{
class Builder
{
public:
struct CutFaceTransform
{
QVector3D translation;
float scale;
QMatrix4x4 rotation;
QVector3D uFactor;
QVector3D vFactor;
bool reverse = false;
};
size_t addNode(const QVector3D &position, float radius, const std::vector<QVector2D> &cutTemplate, float cutRotation);
size_t addEdge(size_t firstNodeIndex, size_t secondNodeIndex);
void setNodeOriginInfo(size_t nodeIndex, int nearOriginNodeIndex, int farOriginNodeIndex);
void setDeformThickness(float thickness);
void setDeformWidth(float width);
void enableBaseNormalOnX(bool enabled);
void enableBaseNormalOnY(bool enabled);
void enableBaseNormalOnZ(bool enabled);
void enableBaseNormalAverage(bool enabled);
const std::vector<QVector3D> &generatedVertices();
const std::vector<std::vector<size_t>> &generatedFaces();
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
void exportAsObj(const QString &filename);
bool build();
const CutFaceTransform *nodeAdjustableCutFaceTransform(size_t nodeIndex);
private:
struct Edge;
struct Node
{
float radius;
QVector3D position;
std::vector<size_t> edges;
std::vector<QVector2D> cutTemplate;
float cutRotation;
std::vector<QVector3D> raysToNeibors;
QVector3D cutNormal;
CutFaceTransform cutFaceTransform;
QVector3D initialTraverseDirection;
QVector3D traverseDirection;
QVector3D growthDirection;
QVector3D initialBaseNormal;
QVector3D baseNormal;
size_t reversedTraverseOrder;
bool hasInitialBaseNormal = false;
bool baseNormalResolved = false;
bool baseNormalSearched = false;
bool hasInitialTraverseDirection = false;
bool hasAdjustableCutFace = false;
int nearOriginNodeIndex = -1;
int farOriginNodeIndex = -1;
size_t anotherEdge(size_t edgeIndex) const
{
if (edges.size() != 2)
return edgeIndex;
const auto &otherIndex = edges[0];
if (otherIndex == edgeIndex)
return edges[1];
return otherIndex;
}
};
struct Edge
{
std::vector<size_t> nodes;
std::vector<std::pair<std::vector<size_t>, QVector3D>> cuts;
size_t neiborOf(size_t nodeIndex) const
{
const auto &otherIndex = nodes[0];
if (otherIndex == nodeIndex)
return nodes[1];
return otherIndex;
}
void updateNodeIndex(size_t fromNodeIndex, size_t toNodeIndex)
{
if (nodes[0] == fromNodeIndex) {
nodes[0] = toNodeIndex;
return;
}
nodes[1] = toNodeIndex;
}
};
std::vector<Node> m_nodes;
std::vector<Edge> m_edges;
std::vector<QVector3D> m_generatedVertices;
std::vector<QVector3D> m_generatedVerticesCutDirects;
std::vector<size_t> m_generatedVerticesSourceNodeIndices;
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<size_t> m_sortedNodeIndices;
std::map<size_t, size_t> m_weldMap;
std::set<size_t> m_swallowedEdges;
std::set<size_t> m_swallowedNodes;
float m_deformThickness = 1.0;
float m_deformWidth = 1.0;
float m_cutRotation = 0.0;
bool m_baseNormalOnX = true;
bool m_baseNormalOnY = true;
bool m_baseNormalOnZ = true;
bool m_baseNormalAverageEnabled = false;
void sortNodeIndices();
void prepareNode(size_t nodeIndex);
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
const std::vector<QVector3D> &inputPositions,
const std::vector<float> &weights);
bool validateNormal(const QVector3D &normal);
void resolveBaseNormalRecursively(size_t nodeIndex);
void resolveBaseNormalForLeavesRecursively(size_t nodeIndex, const QVector3D &baseNormal);
std::pair<QVector3D, bool> searchBaseNormalFromNeighborsRecursively(size_t nodeIndex);
QVector3D revisedBaseNormalAcordingToCutNormal(const QVector3D &baseNormal, const QVector3D &cutNormal);
void resolveInitialTraverseDirectionRecursively(size_t nodeIndex, const QVector3D *from, std::set<size_t> *visited);
void unifyBaseNormals();
void localAverageBaseNormals();
void resolveTraverseDirection(size_t nodeIndex);
bool generateCutsForNode(size_t nodeIndex);
bool tryWrapMultipleBranchesForNode(size_t nodeIndex, std::vector<float> &offsets, bool &offsetsChanged);
void makeCut(const QVector3D &position,
float radius,
const std::vector<QVector2D> &cutTemplate,
float cutRotation,
QVector3D &baseNormal,
QVector3D &cutNormal,
const QVector3D &traverseDirection,
std::vector<QVector3D> &resultCut,
CutFaceTransform *cutFaceTransform=nullptr);
void insertCutVertices(const std::vector<QVector3D> &cut, std::vector<size_t> &vertices, size_t nodeIndex, const QVector3D &cutDirect);
void stitchEdgeCuts();
void applyWeld();
void applyDeform();
QVector3D calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor);
bool swallowEdgeForNode(size_t nodeIndex, size_t edgeOrder);
static QVector3D calculateBaseNormalFromTraverseDirection(const QVector3D &traverseDirection);
};
}
#endif