2021SC@SDUSC
目录
一、MeshGenerator类
继承QObject类
(一)QObject类
QObject类是所有QT对象的基类,还是“Qt中的对象模型”的核心类,其中最重要的功能就是“信号-槽”机制,“信号-槽”机制实现Qt对象之间的无缝交互
以往点击按钮实现功能是通过回调函数与处理函数进行的,处理函数可以在适合的时候调用回调函数,但回调函数并不是类型安全的;并且回调函数与处理函数是强耦合的,处理函数必须要知道调用哪个回调函数
信号与槽能代替上面的机制:在发生某一个特定事件的时候会产生一个信号,槽函数会接收特定的信号并且发出响应。因此,信号-槽机制是类型安全的,因为信号的签名与接收此信号的槽的签名一定是匹配的,不然无法实现接收功能
(二)MeshGenerator类
MeshGenerator类的信号函数:void finished();
槽函数:void process();
class MeshGenerator : public QObject
{
Q_OBJECT
public:
MeshGenerator(Snapshot *snapshot);
~MeshGenerator();
bool isSuccessful();
Model *takeResultMesh();
Model *takePartPreviewMesh(const QUuid &partId);
QImage *takePartPreviewImage(const QUuid &partId);
const std::set<QUuid> &generatedPreviewPartIds();
const std::set<QUuid> &generatedPreviewImagePartIds();
Object *takeObject();
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *takeCutFaceTransforms();
std::map<QUuid, std::map<QString, QVector2D>> *takeNodesCutFaces();
void generate();
void setGeneratedCacheContext(GeneratedCacheContext *cacheContext);
void setSmoothShadingThresholdAngleDegrees(float degrees);
void setInterpolationEnabled(bool interpolationEnabled);
void setDefaultPartColor(const QColor &color);
void setId(quint64 id);
void setWeldEnabled(bool enabled);
quint64 id();
signals:
void finished();
public slots:
void process();
private:
QColor m_defaultPartColor = Qt::white;
Snapshot *m_snapshot = nullptr;
GeneratedCacheContext *m_cacheContext = nullptr;
//脏标记位
std::set<QString> m_dirtyComponentIds;
std::set<QString> m_dirtyPartIds;
float m_mainProfileMiddleX = 0;
float m_sideProfileMiddleX = 0;
float m_mainProfileMiddleY = 0;
Object *m_object = nullptr;
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> m_nodeVertices;//顶点的位置及索引
std::map<QString, std::set<QString>> m_partNodeIds;//存储顶点信息
std::map<QString, std::set<QString>> m_partEdgeIds;//存储边信息
std::set<QUuid> m_generatedPreviewPartIds;
std::set<QUuid> m_generatedPreviewImagePartIds;
Model *m_resultMesh = nullptr;
std::map<QUuid, Model *> m_partPreviewMeshes;
std::map<QUuid, QImage *> m_partPreviewImages;
bool m_isSuccessful = false;
bool m_cacheEnabled = false;
float m_smoothShadingThresholdAngleDegrees = 60;//渲染角度阈值
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_cutFaceTransforms = nullptr;
std::map<QUuid, std::map<QString, QVector2D>> *m_nodesCutFaces = nullptr;
quint64 m_id = 0;
std::vector<QVector3D> m_clothCollisionVertices;
std::vector<std::vector<size_t>> m_clothCollisionTriangles;
//焊接与插值
bool m_weldEnabled = true;
bool m_interpolationEnabled = true;
//
void collectParts();
void collectIncombinableComponentMeshes(const QString &componentIdString);
void collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache);
//与脏标记相关:
bool checkIsComponentDirty(const QString &componentIdString);
bool checkIsPartDirty(const QString &partIdString);
bool checkIsPartDependencyDirty(const QString &partIdString);
void checkDirtyFlags();
bool fillPartWithMesh(GeneratedPart &partCache,
const QUuid &fillMeshFileId,
float deformThickness,
float deformWidth,
float cutRotation,
const StrokeMeshBuilder *strokeMeshBuilder);
MeshCombiner::Mesh *combinePartMesh(const QString &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes=true);
MeshCombiner::Mesh *combineComponentMesh(const QString &componentIdString, CombineMode *combineMode);
void makeXmirror(const std::vector<QVector3D> &sourceVertices, const std::vector<std::vector<size_t>> &sourceFaces,
std::vector<QVector3D> *destVertices, std::vector<std::vector<size_t>> *destFaces);
void collectSharedQuadEdges(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces,
std::set<std::pair<PositionKey, PositionKey>> *sharedQuadEdges);
MeshCombiner::Mesh *combineTwoMeshes(const MeshCombiner::Mesh &first, const MeshCombiner::Mesh &second,
MeshCombiner::Method method,
bool recombine=true);
void generateSmoothTriangleVertexNormals(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
const std::vector<QVector3D> &triangleNormals,
std::vector<std::vector<QVector3D>> *triangleVertexNormals);
const std::map<QString, QString> *findComponent(const QString &componentIdString);
CombineMode componentCombineMode(const std::map<QString, QString> *component);
MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
GeneratedComponent &componentCache);
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
QString componentColorName(const std::map<QString, QString> *component);
void collectUncombinedComponent(const QString &componentIdString);
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
void postprocessObject(Object *object);//后处理
void collectErroredParts();
void preprocessMirror();//镜面处理
QString reverseUuid(const QString &uuidString);
};
二、重要函数
1.generate函数
首先进行镜像处理,之后不断循环迭代cacheContext,得到它们的镜像部分,直到形成完整对称的几何体,完成镜像处理,之后再对合并网格进行焊接并再检查没有进行合并的网格,对没有进行合并的网格进行处理。最后,使用后处理完善模型m_object,生成新的模型
void MeshGenerator::generate()
{
if (nullptr == m_snapshot)
return;
m_isSuccessful = true;
QElapsedTimer countTimeConsumed;//添加计时器
countTimeConsumed.start();
//获得canvas的位置
m_mainProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat();
m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
preprocessMirror();//镜像处理
m_object = new Object;
m_object->meshId = m_id;
//m_cutFaceTransforms = new std::map<QUuid, nodemesh::Builder::CutFaceTransform>;
//m_nodesCutFaces = new std::map<QUuid, std::map<QString, QVector2D>>;
bool needDeleteCacheContext = false;//用于表示CacheContext是否存在
if (nullptr == m_cacheContext) {
m_cacheContext = new GeneratedCacheContext;
needDeleteCacheContext = true;
} else {
m_cacheEnabled = true;
//parts
for (auto it = m_cacheContext->parts.begin(); it != m_cacheContext->parts.end(); ) {
if (m_snapshot->parts.find(it->first) == m_snapshot->parts.end()) {
//在partMirrorIdMap中找到mirrorFrom并加进cacheContext
auto mirrorFrom = m_cacheContext->partMirrorIdMap.find(it->first);
if (mirrorFrom != m_cacheContext->partMirrorIdMap.end()) {
if (m_snapshot->parts.find(mirrorFrom->second) != m_snapshot->parts.end()) {
it++;
continue;
}
m_cacheContext->partMirrorIdMap.erase(mirrorFrom);
}
it->second.releaseMeshes();
it = m_cacheContext->parts.erase(it);
continue;
}
it++;
}
//components
for (auto it = m_cacheContext->components.begin(); it != m_cacheContext->components.end(); ) {
if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) {
for (auto combinationIt = m_cacheContext->cachedCombination.begin(); combinationIt != m_cacheContext->cachedCombination.end(); ) {
if (-1 != combinationIt->first.indexOf(it->first)) {
//qDebug() << "Removed cached combination:" << combinationIt->first;
delete combinationIt->second;
combinationIt = m_cacheContext->cachedCombination.erase(combinationIt);
continue;
}
combinationIt++;
}
it->second.releaseMeshes();
it = m_cacheContext->components.erase(it);
continue;
}
it++;
}
}
collectParts();//存储点和边的信息
checkDirtyFlags();
//用dirty位进行优化加速
for (const auto &dirtyComponentId: m_dirtyComponentIds) {
for (auto combinationIt = m_cacheContext->cachedCombination.begin(); combinationIt != m_cacheContext->cachedCombination.end(); ) {
if (-1 != combinationIt->first.indexOf(dirtyComponentId)) {
//qDebug() << "Removed dirty cached combination:" << combinationIt->first;
delete combinationIt->second;
combinationIt = m_cacheContext->cachedCombination.erase(combinationIt);
continue;
}
combinationIt++;
}
}
m_dirtyComponentIds.insert(QUuid().toString());
//进行组合
CombineMode combineMode;
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
const auto &componentCache = m_cacheContext->components[QUuid().toString()];
m_object->nodes = componentCache.objectNodes;
m_object->edges = componentCache.objectEdges;
m_nodeVertices = componentCache.objectNodeVertices;
std::vector<QVector3D> combinedVertices;
std::vector<std::vector<size_t>> combinedFaces;
if (nullptr != combinedMesh) {
combinedMesh->fetch(combinedVertices, combinedFaces);
//焊接
if (m_weldEnabled) {
size_t totalAffectedNum = 0;
size_t affectedNum = 0;
do {
std::vector<QVector3D> weldedVertices;
std::vector<std::vector<size_t>> weldedFaces;
affectedNum = weldSeam(combinedVertices, combinedFaces,
0.025, componentCache.noneSeamVertices,
weldedVertices, weldedFaces);
//将两个面焊接起来
combinedVertices = weldedVertices;
combinedFaces = weldedFaces;
totalAffectedNum += affectedNum;
} while (affectedNum > 0);
}
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
//处理经过焊接的部分
m_object->vertices = combinedVertices;
m_object->triangles = combinedFaces;
}
// 递归检查未组合的组件
collectUncombinedComponent(QUuid().toString());
collectIncombinableComponentMeshes(QUuid().toString());
collectErroredParts();
postprocessObject(m_object);//后处理
m_resultMesh = new Model(*m_object);//生成新模型
delete combinedMesh;
if (needDeleteCacheContext) {
delete m_cacheContext;
m_cacheContext = nullptr;
}
qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
}
2.reverseUuid函数
实现Uuid(唯一码)的倒转,用于实现镜面效果
QString MeshGenerator::reverseUuid(const QString &uuidString)
{
QUuid uuid(uuidString);
QString newIdString = uuid.toString();
QString newRawId = newIdString.mid(1, 8) +
newIdString.mid(10, 4) +
newIdString.mid(15, 4) +
newIdString.mid(20, 4) +
newIdString.mid(25, 12);
std::reverse(newRawId.begin(), newRawId.end());
return "{" + newRawId.mid(0, 8) + "-" +
newRawId.mid(8, 4) + "-" +
newRawId.mid(12, 4) + "-" +
newRawId.mid(16, 4) + "-" +
newRawId.mid(20, 12) + "}";
}
3.collectIncombinableMesh函数
调用recoverQuads将没有合并的四边形与三角形面都放入到uncombinedTriangleAndQuads中
用updateVertexIndices经过两次循环得到所有没有合并的面数
最后将没有合并的点、面与m_object进行合并
void MeshGenerator::collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache)
{
if (nullptr == mesh)
return;
//获取未合并点与面的信息
std::vector<QVector3D> uncombinedVertices;
std::vector<std::vector<size_t>> uncombinedFaces;
mesh->fetch(uncombinedVertices, uncombinedFaces);
std::vector<std::vector<size_t>> uncombinedTriangleAndQuads;
//将没有合并的四边形与三角形面合并
recoverQuads(uncombinedVertices, uncombinedFaces, componentCache.sharedQuadEdges, uncombinedTriangleAndQuads);
//迭代得出所有数量
auto vertexStartIndex = m_object->vertices.size();
auto updateVertexIndices = [=](std::vector<std::vector<size_t>> &faces) {
for (auto &it: faces) {
for (auto &subIt: it)
subIt += vertexStartIndex;
}
};
//使用updateVertexIndices得出未合并的所有面数
updateVertexIndices(uncombinedFaces);
updateVertexIndices(uncombinedTriangleAndQuads);
//将未合并的点、面与m_object合并
m_object->vertices.insert(m_object->vertices.end(), uncombinedVertices.begin(), uncombinedVertices.end());
m_object->triangles.insert(m_object->triangles.end(), uncombinedFaces.begin(), uncombinedFaces.end());
m_object->triangleAndQuads.insert(m_object->triangleAndQuads.end(), uncombinedTriangleAndQuads.begin(), uncombinedTriangleAndQuads.end());
}