2018-04-07 08:44:39 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <QGuiApplication>
|
|
|
|
#include "meshgenerator.h"
|
2018-05-07 16:08:19 +00:00
|
|
|
#include "dust3dutil.h"
|
2018-04-07 08:44:39 +00:00
|
|
|
#include "skeletondocument.h"
|
|
|
|
#include "meshlite.h"
|
|
|
|
#include "modelofflinerender.h"
|
2018-04-08 08:05:12 +00:00
|
|
|
#include "meshutil.h"
|
2018-04-07 08:44:39 +00:00
|
|
|
#include "theme.h"
|
2018-04-26 02:23:22 +00:00
|
|
|
#include "positionmap.h"
|
2018-04-07 08:44:39 +00:00
|
|
|
|
2018-04-11 06:15:11 +00:00
|
|
|
bool MeshGenerator::enableDebug = false;
|
2018-05-10 09:16:22 +00:00
|
|
|
bool MeshGenerator::disableUnion = false;
|
2018-04-11 06:15:11 +00:00
|
|
|
|
2018-04-07 08:44:39 +00:00
|
|
|
MeshGenerator::MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread) :
|
|
|
|
m_snapshot(snapshot),
|
|
|
|
m_mesh(nullptr),
|
|
|
|
m_preview(nullptr),
|
|
|
|
m_requirePreview(false),
|
|
|
|
m_previewRender(nullptr),
|
2018-04-26 02:23:22 +00:00
|
|
|
m_thread(thread),
|
|
|
|
m_meshResultContext(nullptr)
|
2018-04-07 08:44:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
MeshGenerator::~MeshGenerator()
|
|
|
|
{
|
|
|
|
delete m_snapshot;
|
|
|
|
delete m_mesh;
|
|
|
|
delete m_preview;
|
|
|
|
for (const auto &partPreviewIt: m_partPreviewMap) {
|
|
|
|
delete partPreviewIt.second;
|
|
|
|
}
|
|
|
|
for (const auto &render: m_partPreviewRenderMap) {
|
|
|
|
delete render.second;
|
|
|
|
}
|
|
|
|
delete m_previewRender;
|
2018-04-26 02:23:22 +00:00
|
|
|
delete m_meshResultContext;
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MeshGenerator::addPreviewRequirement()
|
|
|
|
{
|
|
|
|
m_requirePreview = true;
|
|
|
|
if (nullptr == m_previewRender) {
|
|
|
|
m_previewRender = new ModelOfflineRender;
|
|
|
|
m_previewRender->setRenderThread(m_thread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshGenerator::addPartPreviewRequirement(const QString &partId)
|
|
|
|
{
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "addPartPreviewRequirement:" << partId;
|
2018-04-07 08:44:39 +00:00
|
|
|
m_requirePartPreviewMap.insert(partId);
|
|
|
|
if (m_partPreviewRenderMap.find(partId) == m_partPreviewRenderMap.end()) {
|
|
|
|
ModelOfflineRender *render = new ModelOfflineRender;
|
|
|
|
render->setRenderThread(m_thread);
|
|
|
|
m_partPreviewRenderMap[partId] = render;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-07 17:16:58 +00:00
|
|
|
MeshLoader *MeshGenerator::takeResultMesh()
|
2018-04-07 08:44:39 +00:00
|
|
|
{
|
2018-05-07 17:16:58 +00:00
|
|
|
MeshLoader *resultMesh = m_mesh;
|
2018-04-07 08:44:39 +00:00
|
|
|
m_mesh = nullptr;
|
|
|
|
return resultMesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
QImage *MeshGenerator::takePreview()
|
|
|
|
{
|
|
|
|
QImage *resultPreview = m_preview;
|
|
|
|
m_preview = nullptr;
|
|
|
|
return resultPreview;
|
|
|
|
}
|
|
|
|
|
|
|
|
QImage *MeshGenerator::takePartPreview(const QString &partId)
|
|
|
|
{
|
|
|
|
QImage *resultImage = m_partPreviewMap[partId];
|
|
|
|
m_partPreviewMap[partId] = nullptr;
|
|
|
|
return resultImage;
|
|
|
|
}
|
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
MeshResultContext *MeshGenerator::takeMeshResultContext()
|
|
|
|
{
|
|
|
|
MeshResultContext *meshResultContext = m_meshResultContext;
|
|
|
|
m_meshResultContext = nullptr;
|
|
|
|
return meshResultContext;
|
|
|
|
}
|
|
|
|
|
2018-04-15 12:11:51 +00:00
|
|
|
void MeshGenerator::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId)
|
2018-04-07 08:44:39 +00:00
|
|
|
{
|
2018-04-15 12:11:51 +00:00
|
|
|
m_snapshot->resolveBoundingBox(mainProfile, sideProfile, partId);
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
void MeshGenerator::loadVertexSourcesToMeshResultContext(void *meshliteContext, int meshId, int bmeshId)
|
|
|
|
{
|
|
|
|
int vertexCount = meshlite_get_vertex_count(meshliteContext, meshId);
|
|
|
|
int positionBufferLen = vertexCount * 3;
|
|
|
|
float *positionBuffer = new float[positionBufferLen];
|
|
|
|
int positionCount = meshlite_get_vertex_position_array(meshliteContext, meshId, positionBuffer, positionBufferLen) / 3;
|
|
|
|
int *sourceBuffer = new int[positionBufferLen];
|
|
|
|
int sourceCount = meshlite_get_vertex_source_array(meshliteContext, meshId, sourceBuffer, positionBufferLen);
|
|
|
|
Q_ASSERT(positionCount == sourceCount);
|
|
|
|
for (int i = 0, positionIndex = 0; i < positionCount; i++, positionIndex+=3) {
|
|
|
|
BmeshVertex vertex;
|
|
|
|
vertex.bmeshId = bmeshId;
|
|
|
|
vertex.nodeId = sourceBuffer[i];
|
|
|
|
vertex.position = QVector3D(positionBuffer[positionIndex + 0], positionBuffer[positionIndex + 1], positionBuffer[positionIndex + 2]);
|
|
|
|
m_meshResultContext->bmeshVertices.push_back(vertex);
|
|
|
|
}
|
|
|
|
delete[] positionBuffer;
|
|
|
|
delete[] sourceBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshGenerator::loadGeneratedPositionsToMeshResultContext(void *meshliteContext, int triangulatedMeshId)
|
|
|
|
{
|
|
|
|
int vertexCount = meshlite_get_vertex_count(meshliteContext, triangulatedMeshId);
|
|
|
|
int positionBufferLen = vertexCount * 3;
|
|
|
|
float *positionBuffer = new float[positionBufferLen];
|
|
|
|
int positionCount = meshlite_get_vertex_position_array(meshliteContext, triangulatedMeshId, positionBuffer, positionBufferLen) / 3;
|
|
|
|
std::map<int, int> verticesMap;
|
|
|
|
for (int i = 0, positionIndex = 0; i < positionCount; i++, positionIndex+=3) {
|
|
|
|
ResultVertex vertex;
|
|
|
|
vertex.position = QVector3D(positionBuffer[positionIndex + 0], positionBuffer[positionIndex + 1], positionBuffer[positionIndex + 2]);
|
2018-05-07 16:08:19 +00:00
|
|
|
verticesMap[i] = m_meshResultContext->vertices.size();
|
|
|
|
m_meshResultContext->vertices.push_back(vertex);
|
2018-04-26 02:23:22 +00:00
|
|
|
}
|
|
|
|
int faceCount = meshlite_get_face_count(meshliteContext, triangulatedMeshId);
|
|
|
|
int triangleIndexBufferLen = faceCount * 3;
|
|
|
|
int *triangleIndexBuffer = new int[triangleIndexBufferLen];
|
|
|
|
int triangleCount = meshlite_get_triangle_index_array(meshliteContext, triangulatedMeshId, triangleIndexBuffer, triangleIndexBufferLen) / 3;
|
|
|
|
int triangleNormalBufferLen = faceCount * 3;
|
|
|
|
float *normalBuffer = new float[triangleNormalBufferLen];
|
|
|
|
int normalCount = meshlite_get_triangle_normal_array(meshliteContext, triangulatedMeshId, normalBuffer, triangleNormalBufferLen) / 3;
|
|
|
|
Q_ASSERT(triangleCount == normalCount);
|
|
|
|
for (int i = 0, triangleVertIndex = 0, normalIndex=0; i < triangleCount; i++, triangleVertIndex+=3, normalIndex += 3) {
|
|
|
|
ResultTriangle triangle;
|
|
|
|
triangle.indicies[0] = verticesMap[triangleIndexBuffer[triangleVertIndex + 0]];
|
|
|
|
triangle.indicies[1] = verticesMap[triangleIndexBuffer[triangleVertIndex + 1]];
|
|
|
|
triangle.indicies[2] = verticesMap[triangleIndexBuffer[triangleVertIndex + 2]];
|
|
|
|
triangle.normal = QVector3D(normalBuffer[normalIndex + 0], normalBuffer[normalIndex + 1], normalBuffer[normalIndex + 2]);
|
2018-05-07 16:08:19 +00:00
|
|
|
m_meshResultContext->triangles.push_back(triangle);
|
2018-04-26 02:23:22 +00:00
|
|
|
}
|
|
|
|
delete[] positionBuffer;
|
|
|
|
delete[] triangleIndexBuffer;
|
|
|
|
delete[] normalBuffer;
|
|
|
|
}
|
|
|
|
|
2018-04-07 08:44:39 +00:00
|
|
|
void MeshGenerator::process()
|
|
|
|
{
|
|
|
|
if (nullptr == m_snapshot)
|
|
|
|
return;
|
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
m_meshResultContext = new MeshResultContext;
|
|
|
|
|
2018-04-07 08:44:39 +00:00
|
|
|
void *meshliteContext = meshlite_create_context();
|
|
|
|
std::map<QString, int> partBmeshMap;
|
|
|
|
std::map<QString, int> bmeshNodeMap;
|
|
|
|
|
|
|
|
QRectF mainProfile, sideProfile;
|
|
|
|
resolveBoundingBox(&mainProfile, &sideProfile);
|
|
|
|
float longHeight = mainProfile.height();
|
|
|
|
if (mainProfile.width() > longHeight)
|
|
|
|
longHeight = mainProfile.width();
|
|
|
|
if (sideProfile.width() > longHeight)
|
|
|
|
longHeight = sideProfile.width();
|
|
|
|
float mainProfileMiddleX = mainProfile.x() + mainProfile.width() / 2;
|
|
|
|
float sideProfileMiddleX = sideProfile.x() + sideProfile.width() / 2;
|
|
|
|
float mainProfileMiddleY = mainProfile.y() + mainProfile.height() / 2;
|
2018-04-15 12:11:51 +00:00
|
|
|
float originX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat();
|
|
|
|
float originY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
|
|
|
|
float originZ = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
|
|
|
|
bool originSettled = false;
|
|
|
|
if (originX > 0 && originY > 0 && originZ > 0) {
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "Use settled origin: " << originX << originY << originZ << " calculated:" << mainProfileMiddleX << mainProfileMiddleY << sideProfileMiddleX;
|
2018-04-15 12:11:51 +00:00
|
|
|
mainProfileMiddleX = originX;
|
|
|
|
mainProfileMiddleY = originY;
|
|
|
|
sideProfileMiddleX = originZ;
|
|
|
|
originSettled = true;
|
|
|
|
} else {
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "No settled origin, calculated:" << mainProfileMiddleX << mainProfileMiddleY << sideProfileMiddleX;
|
2018-04-15 12:11:51 +00:00
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
std::map<QString, QColor> partColorMap;
|
2018-04-30 11:31:09 +00:00
|
|
|
std::map<QString, bool> partMirrorFlagMap;
|
2018-04-26 02:23:22 +00:00
|
|
|
|
2018-04-07 08:44:39 +00:00
|
|
|
for (const auto &partIdIt: m_snapshot->partIdList) {
|
2018-04-11 09:19:27 +00:00
|
|
|
const auto &part = m_snapshot->parts.find(partIdIt);
|
|
|
|
if (part == m_snapshot->parts.end())
|
|
|
|
continue;
|
|
|
|
QString disabledString = valueOfKeyInMapOrEmpty(part->second, "disabled");
|
|
|
|
bool isDisabled = isTrueValueString(disabledString);
|
|
|
|
if (isDisabled)
|
|
|
|
continue;
|
2018-04-16 00:58:04 +00:00
|
|
|
bool subdived = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "subdived"));
|
2018-04-07 08:44:39 +00:00
|
|
|
int bmeshId = meshlite_bmesh_create(meshliteContext);
|
2018-04-16 00:58:04 +00:00
|
|
|
if (subdived)
|
|
|
|
meshlite_bmesh_set_cut_subdiv_count(meshliteContext, bmeshId, 1);
|
2018-04-26 02:23:22 +00:00
|
|
|
if (isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "rounded")))
|
|
|
|
meshlite_bmesh_set_round_way(meshliteContext, bmeshId, 1);
|
2018-04-30 11:31:09 +00:00
|
|
|
partMirrorFlagMap[partIdIt] = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "xMirrored"));
|
2018-04-26 02:23:22 +00:00
|
|
|
QString colorString = valueOfKeyInMapOrEmpty(part->second, "color");
|
|
|
|
QColor partColor = colorString.isEmpty() ? Theme::white : QColor(colorString);
|
|
|
|
partColorMap[partIdIt] = partColor;
|
2018-04-17 16:14:31 +00:00
|
|
|
QString thicknessString = valueOfKeyInMapOrEmpty(part->second, "deformThickness");
|
2018-04-17 13:13:32 +00:00
|
|
|
if (!thicknessString.isEmpty())
|
2018-04-17 16:14:31 +00:00
|
|
|
meshlite_bmesh_set_deform_thickness(meshliteContext, bmeshId, thicknessString.toFloat());
|
|
|
|
QString widthString = valueOfKeyInMapOrEmpty(part->second, "deformWidth");
|
|
|
|
if (!widthString.isEmpty())
|
|
|
|
meshlite_bmesh_set_deform_width(meshliteContext, bmeshId, widthString.toFloat());
|
2018-04-11 06:15:11 +00:00
|
|
|
if (MeshGenerator::enableDebug)
|
|
|
|
meshlite_bmesh_enable_debug(meshliteContext, bmeshId, 1);
|
2018-04-07 08:44:39 +00:00
|
|
|
partBmeshMap[partIdIt] = bmeshId;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &edgeIt: m_snapshot->edges) {
|
|
|
|
QString partId = valueOfKeyInMapOrEmpty(edgeIt.second, "partId");
|
|
|
|
QString fromNodeId = valueOfKeyInMapOrEmpty(edgeIt.second, "from");
|
|
|
|
QString toNodeId = valueOfKeyInMapOrEmpty(edgeIt.second, "to");
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "Processing edge " << fromNodeId << "<=>" << toNodeId;
|
2018-04-07 08:44:39 +00:00
|
|
|
const auto fromIt = m_snapshot->nodes.find(fromNodeId);
|
|
|
|
const auto toIt = m_snapshot->nodes.find(toNodeId);
|
|
|
|
if (fromIt == m_snapshot->nodes.end() || toIt == m_snapshot->nodes.end())
|
|
|
|
continue;
|
|
|
|
const auto partBmeshIt = partBmeshMap.find(partId);
|
|
|
|
if (partBmeshIt == partBmeshMap.end())
|
|
|
|
continue;
|
|
|
|
int bmeshId = partBmeshIt->second;
|
|
|
|
|
|
|
|
int bmeshFromNodeId = 0;
|
|
|
|
const auto bmeshFromIt = bmeshNodeMap.find(fromNodeId);
|
|
|
|
if (bmeshFromIt == bmeshNodeMap.end()) {
|
|
|
|
float radius = valueOfKeyInMapOrEmpty(fromIt->second, "radius").toFloat() / longHeight;
|
|
|
|
float x = (valueOfKeyInMapOrEmpty(fromIt->second, "x").toFloat() - mainProfileMiddleX) / longHeight;
|
2018-04-20 12:00:57 +00:00
|
|
|
float y = (mainProfileMiddleY - valueOfKeyInMapOrEmpty(fromIt->second, "y").toFloat()) / longHeight;
|
|
|
|
float z = (sideProfileMiddleX - valueOfKeyInMapOrEmpty(fromIt->second, "z").toFloat()) / longHeight;
|
2018-04-07 08:44:39 +00:00
|
|
|
bmeshFromNodeId = meshlite_bmesh_add_node(meshliteContext, bmeshId, x, y, z, radius);
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "bmeshId[" << bmeshId << "] add node[" << bmeshFromNodeId << "]" << radius << x << y << z;
|
2018-04-07 08:44:39 +00:00
|
|
|
bmeshNodeMap[fromNodeId] = bmeshFromNodeId;
|
2018-04-26 02:23:22 +00:00
|
|
|
|
2018-05-30 01:51:38 +00:00
|
|
|
SkeletonBoneMark boneMark = SkeletonBoneMarkFromString(valueOfKeyInMapOrEmpty(fromIt->second, "boneMark").toUtf8().constData());
|
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
BmeshNode bmeshNode;
|
|
|
|
bmeshNode.bmeshId = bmeshId;
|
|
|
|
bmeshNode.origin = QVector3D(x, y, z);
|
|
|
|
bmeshNode.radius = radius;
|
|
|
|
bmeshNode.nodeId = bmeshFromNodeId;
|
|
|
|
bmeshNode.color = partColorMap[partId];
|
2018-05-30 01:51:38 +00:00
|
|
|
bmeshNode.boneMark = boneMark;
|
2018-04-26 02:23:22 +00:00
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
2018-04-30 11:31:09 +00:00
|
|
|
|
|
|
|
if (partMirrorFlagMap[partId]) {
|
|
|
|
bmeshNode.bmeshId = -bmeshId;
|
|
|
|
bmeshNode.origin.setX(-x);
|
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
} else {
|
|
|
|
bmeshFromNodeId = bmeshFromIt->second;
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "bmeshId[" << bmeshId << "] use existed node[" << bmeshFromNodeId << "]";
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int bmeshToNodeId = 0;
|
|
|
|
const auto bmeshToIt = bmeshNodeMap.find(toNodeId);
|
|
|
|
if (bmeshToIt == bmeshNodeMap.end()) {
|
|
|
|
float radius = valueOfKeyInMapOrEmpty(toIt->second, "radius").toFloat() / longHeight;
|
|
|
|
float x = (valueOfKeyInMapOrEmpty(toIt->second, "x").toFloat() - mainProfileMiddleX) / longHeight;
|
2018-04-20 12:00:57 +00:00
|
|
|
float y = (mainProfileMiddleY - valueOfKeyInMapOrEmpty(toIt->second, "y").toFloat()) / longHeight;
|
|
|
|
float z = (sideProfileMiddleX - valueOfKeyInMapOrEmpty(toIt->second, "z").toFloat()) / longHeight;
|
2018-04-07 08:44:39 +00:00
|
|
|
bmeshToNodeId = meshlite_bmesh_add_node(meshliteContext, bmeshId, x, y, z, radius);
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "bmeshId[" << bmeshId << "] add node[" << bmeshToNodeId << "]" << radius << x << y << z;
|
2018-04-07 08:44:39 +00:00
|
|
|
bmeshNodeMap[toNodeId] = bmeshToNodeId;
|
2018-04-26 02:23:22 +00:00
|
|
|
|
2018-05-30 01:51:38 +00:00
|
|
|
SkeletonBoneMark boneMark = SkeletonBoneMarkFromString(valueOfKeyInMapOrEmpty(toIt->second, "boneMark").toUtf8().constData());
|
|
|
|
|
2018-04-26 02:23:22 +00:00
|
|
|
BmeshNode bmeshNode;
|
|
|
|
bmeshNode.bmeshId = bmeshId;
|
|
|
|
bmeshNode.origin = QVector3D(x, y, z);
|
|
|
|
bmeshNode.radius = radius;
|
|
|
|
bmeshNode.nodeId = bmeshToNodeId;
|
|
|
|
bmeshNode.color = partColorMap[partId];
|
2018-05-30 01:51:38 +00:00
|
|
|
bmeshNode.boneMark = boneMark;
|
2018-04-26 02:23:22 +00:00
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
2018-04-30 11:31:09 +00:00
|
|
|
|
|
|
|
if (partMirrorFlagMap[partId]) {
|
|
|
|
bmeshNode.bmeshId = -bmeshId;
|
|
|
|
bmeshNode.origin.setX(-x);
|
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
} else {
|
|
|
|
bmeshToNodeId = bmeshToIt->second;
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "bmeshId[" << bmeshId << "] use existed node[" << bmeshToNodeId << "]";
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
meshlite_bmesh_add_edge(meshliteContext, bmeshId, bmeshFromNodeId, bmeshToNodeId);
|
2018-04-26 02:23:22 +00:00
|
|
|
|
|
|
|
BmeshEdge bmeshEdge;
|
2018-04-30 11:31:09 +00:00
|
|
|
bmeshEdge.fromBmeshId = bmeshId;
|
2018-04-26 02:23:22 +00:00
|
|
|
bmeshEdge.fromNodeId = bmeshFromNodeId;
|
2018-04-30 11:31:09 +00:00
|
|
|
bmeshEdge.toBmeshId = bmeshId;
|
2018-04-26 02:23:22 +00:00
|
|
|
bmeshEdge.toNodeId = bmeshToNodeId;
|
|
|
|
m_meshResultContext->bmeshEdges.push_back(bmeshEdge);
|
2018-04-30 11:31:09 +00:00
|
|
|
|
|
|
|
if (partMirrorFlagMap[partId]) {
|
|
|
|
BmeshEdge bmeshEdge;
|
|
|
|
bmeshEdge.fromBmeshId = -bmeshId;
|
|
|
|
bmeshEdge.fromNodeId = bmeshFromNodeId;
|
|
|
|
bmeshEdge.toBmeshId = -bmeshId;
|
|
|
|
bmeshEdge.toNodeId = bmeshToNodeId;
|
|
|
|
m_meshResultContext->bmeshEdges.push_back(bmeshEdge);
|
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
2018-04-09 11:13:34 +00:00
|
|
|
for (const auto &nodeIt: m_snapshot->nodes) {
|
|
|
|
QString partId = valueOfKeyInMapOrEmpty(nodeIt.second, "partId");
|
|
|
|
const auto partBmeshIt = partBmeshMap.find(partId);
|
|
|
|
if (partBmeshIt == partBmeshMap.end())
|
|
|
|
continue;
|
|
|
|
const auto nodeBmeshIt = bmeshNodeMap.find(nodeIt.first);
|
|
|
|
if (nodeBmeshIt != bmeshNodeMap.end())
|
|
|
|
continue;
|
|
|
|
int bmeshId = partBmeshIt->second;
|
|
|
|
float radius = valueOfKeyInMapOrEmpty(nodeIt.second, "radius").toFloat() / longHeight;
|
|
|
|
float x = (valueOfKeyInMapOrEmpty(nodeIt.second, "x").toFloat() - mainProfileMiddleX) / longHeight;
|
2018-04-20 12:00:57 +00:00
|
|
|
float y = (mainProfileMiddleY - valueOfKeyInMapOrEmpty(nodeIt.second, "y").toFloat()) / longHeight;
|
|
|
|
float z = (sideProfileMiddleX - valueOfKeyInMapOrEmpty(nodeIt.second, "z").toFloat()) / longHeight;
|
2018-04-09 11:13:34 +00:00
|
|
|
int bmeshNodeId = meshlite_bmesh_add_node(meshliteContext, bmeshId, x, y, z, radius);
|
2018-04-15 15:15:29 +00:00
|
|
|
//qDebug() << "bmeshId[" << bmeshId << "] add lonely node[" << bmeshNodeId << "]" << radius << x << y << z;
|
2018-04-09 11:13:34 +00:00
|
|
|
bmeshNodeMap[nodeIt.first] = bmeshNodeId;
|
2018-04-26 02:23:22 +00:00
|
|
|
|
|
|
|
BmeshNode bmeshNode;
|
|
|
|
bmeshNode.bmeshId = bmeshId;
|
|
|
|
bmeshNode.origin = QVector3D(x, y, z);
|
|
|
|
bmeshNode.radius = radius;
|
|
|
|
bmeshNode.nodeId = bmeshNodeId;
|
|
|
|
bmeshNode.color = partColorMap[partId];
|
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
2018-04-30 11:31:09 +00:00
|
|
|
|
|
|
|
if (partMirrorFlagMap[partId]) {
|
|
|
|
bmeshNode.bmeshId = -bmeshId;
|
|
|
|
bmeshNode.origin.setX(-x);
|
|
|
|
m_meshResultContext->bmeshNodes.push_back(bmeshNode);
|
|
|
|
}
|
2018-04-09 11:13:34 +00:00
|
|
|
}
|
|
|
|
|
2018-04-11 09:37:28 +00:00
|
|
|
bool broken = false;
|
|
|
|
|
2018-04-07 08:44:39 +00:00
|
|
|
std::vector<int> meshIds;
|
2018-04-11 06:15:11 +00:00
|
|
|
std::vector<int> subdivMeshIds;
|
2018-04-07 08:44:39 +00:00
|
|
|
for (const auto &partIdIt: m_snapshot->partIdList) {
|
2018-04-11 09:19:27 +00:00
|
|
|
const auto &part = m_snapshot->parts.find(partIdIt);
|
|
|
|
if (part == m_snapshot->parts.end())
|
|
|
|
continue;
|
|
|
|
QString disabledString = valueOfKeyInMapOrEmpty(part->second, "disabled");
|
|
|
|
bool isDisabled = isTrueValueString(disabledString);
|
|
|
|
if (isDisabled)
|
|
|
|
continue;
|
2018-04-07 08:44:39 +00:00
|
|
|
int bmeshId = partBmeshMap[partIdIt];
|
2018-04-11 06:15:11 +00:00
|
|
|
int meshId = meshlite_bmesh_generate_mesh(meshliteContext, bmeshId);
|
2018-04-11 09:37:28 +00:00
|
|
|
if (meshlite_bmesh_error_count(meshliteContext, bmeshId) != 0)
|
|
|
|
broken = true;
|
2018-04-15 12:11:51 +00:00
|
|
|
bool xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "xMirrored"));
|
2018-04-26 02:23:22 +00:00
|
|
|
loadVertexSourcesToMeshResultContext(meshliteContext, meshId, bmeshId);
|
|
|
|
QColor modelColor = partColorMap[partIdIt];
|
2018-04-15 12:11:51 +00:00
|
|
|
int xMirroredMeshId = 0;
|
2018-04-30 11:31:09 +00:00
|
|
|
if (xMirrored) {
|
2018-04-15 12:11:51 +00:00
|
|
|
if (xMirrored) {
|
|
|
|
xMirroredMeshId = meshlite_mirror_in_x(meshliteContext, meshId, 0);
|
2018-04-30 11:31:09 +00:00
|
|
|
loadVertexSourcesToMeshResultContext(meshliteContext, xMirroredMeshId, -bmeshId);
|
2018-04-15 12:11:51 +00:00
|
|
|
}
|
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
if (m_requirePartPreviewMap.find(partIdIt) != m_requirePartPreviewMap.end()) {
|
|
|
|
ModelOfflineRender *render = m_partPreviewRenderMap[partIdIt];
|
2018-04-07 11:51:33 +00:00
|
|
|
int trimedMeshId = meshlite_trim(meshliteContext, meshId, 1);
|
2018-05-07 17:16:58 +00:00
|
|
|
render->updateMesh(new MeshLoader(meshliteContext, trimedMeshId, -1, modelColor));
|
2018-04-23 00:10:01 +00:00
|
|
|
QImage *image = new QImage(render->toImage(QSize(Theme::previewImageRenderSize, Theme::previewImageRenderSize)));
|
2018-04-07 08:44:39 +00:00
|
|
|
m_partPreviewMap[partIdIt] = image;
|
|
|
|
}
|
2018-04-16 12:06:48 +00:00
|
|
|
meshIds.push_back(meshId);
|
|
|
|
if (xMirroredMeshId)
|
|
|
|
meshIds.push_back(xMirroredMeshId);
|
2018-04-11 06:15:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!subdivMeshIds.empty()) {
|
|
|
|
int mergedMeshId = 0;
|
2018-04-11 09:37:28 +00:00
|
|
|
if (subdivMeshIds.size() > 1) {
|
|
|
|
int errorCount = 0;
|
|
|
|
mergedMeshId = unionMeshs(meshliteContext, subdivMeshIds, &errorCount);
|
|
|
|
if (errorCount)
|
|
|
|
broken = true;
|
|
|
|
} else {
|
|
|
|
mergedMeshId = subdivMeshIds[0];
|
|
|
|
}
|
2018-04-15 15:15:29 +00:00
|
|
|
//if (mergedMeshId > 0)
|
|
|
|
// mergedMeshId = meshlite_combine_coplanar_faces(meshliteContext, mergedMeshId);
|
2018-04-11 06:15:11 +00:00
|
|
|
if (mergedMeshId > 0) {
|
2018-04-11 12:49:00 +00:00
|
|
|
int errorCount = 0;
|
|
|
|
int subdivedMeshId = subdivMesh(meshliteContext, mergedMeshId, &errorCount);
|
|
|
|
if (errorCount > 0)
|
|
|
|
broken = true;
|
2018-04-11 06:15:11 +00:00
|
|
|
if (subdivedMeshId > 0)
|
|
|
|
mergedMeshId = subdivedMeshId;
|
|
|
|
else
|
|
|
|
broken = true;
|
|
|
|
}
|
|
|
|
if (mergedMeshId > 0)
|
|
|
|
meshIds.push_back(mergedMeshId);
|
|
|
|
else
|
|
|
|
broken = true;
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mergedMeshId = 0;
|
2018-04-23 00:10:01 +00:00
|
|
|
if (meshIds.size() > 0) {
|
2018-04-11 06:15:11 +00:00
|
|
|
int errorCount = 0;
|
2018-05-10 09:16:22 +00:00
|
|
|
if (disableUnion)
|
|
|
|
mergedMeshId = mergeMeshs(meshliteContext, meshIds);
|
|
|
|
else
|
|
|
|
mergedMeshId = unionMeshs(meshliteContext, meshIds, &errorCount);
|
2018-04-11 06:15:11 +00:00
|
|
|
if (errorCount)
|
|
|
|
broken = true;
|
2018-04-15 15:55:48 +00:00
|
|
|
else if (mergedMeshId > 0)
|
|
|
|
mergedMeshId = meshlite_combine_coplanar_faces(meshliteContext, mergedMeshId);
|
|
|
|
if (mergedMeshId > 0)
|
|
|
|
mergedMeshId = meshlite_fix_hole(meshliteContext, mergedMeshId);
|
2018-04-08 08:05:12 +00:00
|
|
|
}
|
2018-04-07 08:44:39 +00:00
|
|
|
|
|
|
|
if (mergedMeshId > 0) {
|
|
|
|
if (m_requirePreview) {
|
2018-05-07 17:16:58 +00:00
|
|
|
m_previewRender->updateMesh(new MeshLoader(meshliteContext, mergedMeshId));
|
2018-04-23 00:10:01 +00:00
|
|
|
QImage *image = new QImage(m_previewRender->toImage(QSize(Theme::previewImageRenderSize, Theme::previewImageRenderSize)));
|
2018-04-07 08:44:39 +00:00
|
|
|
m_preview = image;
|
|
|
|
}
|
2018-04-15 12:11:51 +00:00
|
|
|
int finalMeshId = mergedMeshId;
|
2018-04-26 02:23:22 +00:00
|
|
|
int triangulatedFinalMeshId = meshlite_triangulate(meshliteContext, mergedMeshId);
|
|
|
|
loadGeneratedPositionsToMeshResultContext(meshliteContext, triangulatedFinalMeshId);
|
2018-05-07 17:16:58 +00:00
|
|
|
m_mesh = new MeshLoader(meshliteContext, finalMeshId, triangulatedFinalMeshId, broken ? Theme::broken : Theme::white, &m_meshResultContext->triangleColors());
|
2018-04-07 08:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_previewRender) {
|
|
|
|
m_previewRender->setRenderThread(QGuiApplication::instance()->thread());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &partPreviewRender: m_partPreviewRenderMap) {
|
|
|
|
partPreviewRender.second->setRenderThread(QGuiApplication::instance()->thread());
|
|
|
|
}
|
|
|
|
|
|
|
|
meshlite_destroy_context(meshliteContext);
|
|
|
|
|
|
|
|
this->moveToThread(QGuiApplication::instance()->thread());
|
|
|
|
|
|
|
|
emit finished();
|
|
|
|
}
|