diff --git a/languages/dust3d_zh_CN.ts b/languages/dust3d_zh_CN.ts index 989504f7..40439624 100644 --- a/languages/dust3d_zh_CN.ts +++ b/languages/dust3d_zh_CN.ts @@ -736,6 +736,10 @@ Tips: Paste Color 粘贴颜色 + + Remeshed + 重新网格化 + PartWidget diff --git a/src/document.cpp b/src/document.cpp index 36254f47..629cefb2 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -37,6 +37,7 @@ Document::Document() : textureAmbientOcclusionImage(nullptr), rigType(RigType::None), weldEnabled(true), + remeshed(false), // private m_isResultMeshObsolete(false), m_meshGenerator(nullptr), @@ -1201,6 +1202,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId component["smoothAll"] = QString::number(componentIt.second.smoothAll); if (componentIt.second.smoothSeamAdjusted()) component["smoothSeam"] = QString::number(componentIt.second.smoothSeam); + if (componentIt.second.remeshed) + component["remeshed"] = "true"; QStringList childIdList; for (const auto &childId: componentIt.second.childrenIds) { childIdList.append(childId.toString()); @@ -1315,6 +1318,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId canvas["originY"] = QString::number(getOriginY()); canvas["originZ"] = QString::number(getOriginZ()); canvas["rigType"] = RigTypeToString(rigType); + if (this->remeshed) + canvas["remeshed"] = "true"; snapshot->canvas = canvas; } } @@ -1472,6 +1477,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste) bool isOriginChanged = false; bool isRigTypeChanged = false; if (!fromPaste) { + this->remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(snapshot.canvas, "remeshed")); const auto &originXit = snapshot.canvas.find("originX"); const auto &originYit = snapshot.canvas.find("originY"); const auto &originZit = snapshot.canvas.find("originZ"); @@ -1704,6 +1710,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste) const auto &smoothSeamIt = componentKv.second.find("smoothSeam"); if (smoothSeamIt != componentKv.second.end()) component.setSmoothSeam(smoothSeamIt->second.toFloat()); + component.remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "remeshed")); //qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name; if ("partId" == linkDataType) { QUuid partId = oldNewIdMap[QUuid(linkData)]; @@ -2488,6 +2495,29 @@ void Document::setComponentExpandState(QUuid componentId, bool expanded) emit optionsChanged(); } +void Document::setComponentRemeshState(QUuid componentId, bool remeshed) +{ + if (componentId.isNull()) { + if (this->remeshed == remeshed) + return; + this->remeshed = remeshed; + emit componentRemeshStateChanged(componentId); + emit skeletonChanged(); + return; + } + + Component *component = (Component *)findComponent(componentId); + if (nullptr == component) + return; + if (component->remeshed == remeshed) + return; + + component->remeshed = remeshed; + component->dirty = true; + emit componentRemeshStateChanged(componentId); + emit skeletonChanged(); +} + void Document::createNewComponentAndMoveThisIn(QUuid componentId) { auto component = componentMap.find(componentId); diff --git a/src/document.h b/src/document.h index ad420862..463be2d1 100644 --- a/src/document.h +++ b/src/document.h @@ -66,6 +66,7 @@ public: bool dirty = true; float smoothAll = 0.0; float smoothSeam = 0.0; + bool remeshed = false; std::vector childrenIds; QString linkData() const { @@ -394,6 +395,7 @@ signals: void componentExpandStateChanged(QUuid componentId); void componentSmoothAllChanged(QUuid componentId); void componentSmoothSeamChanged(QUuid componentId); + void componentRemeshStateChanged(QUuid componentId); void nodeRemoved(QUuid nodeId); void edgeRemoved(QUuid edgeId); void nodeRadiusChanged(QUuid nodeId); @@ -503,6 +505,7 @@ public: // need initialize QImage *textureAmbientOcclusionImage; RigType rigType; bool weldEnabled; + bool remeshed; public: Document(); ~Document(); @@ -647,6 +650,7 @@ public slots: void setComponentExpandState(QUuid componentId, bool expanded); void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); + void setComponentRemeshState(QUuid componentId, bool remeshed); void hideOtherComponents(QUuid componentId); void lockOtherComponents(QUuid componentId); void hideAllComponents(); diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp index 788005c9..0c3ca330 100644 --- a/src/documentwindow.cpp +++ b/src/documentwindow.cpp @@ -997,6 +997,7 @@ DocumentWindow::DocumentWindow() : connect(partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState); connect(partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll); connect(partTreeWidget, &PartTreeWidget::setComponentSmoothSeam, m_document, &Document::setComponentSmoothSeam); + connect(partTreeWidget, &PartTreeWidget::setComponentRemeshState, m_document, &Document::setComponentRemeshState); connect(partTreeWidget, &PartTreeWidget::moveComponent, m_document, &Document::moveComponent); connect(partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent); connect(partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents); diff --git a/src/meshcombiner.cpp b/src/meshcombiner.cpp index 43179071..4f58bbd6 100644 --- a/src/meshcombiner.cpp +++ b/src/meshcombiner.cpp @@ -10,7 +10,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel; typedef CGAL::Surface_mesh CgalMesh; -MeshCombiner::Mesh::Mesh(const std::vector &vertices, const std::vector> &faces, bool removeSelfIntersects) +MeshCombiner::Mesh::Mesh(const std::vector &vertices, const std::vector> &faces, bool disableSelfIntersects) { CgalMesh *cgalMesh = nullptr; if (!faces.empty()) { @@ -21,15 +21,9 @@ MeshCombiner::Mesh::Mesh(const std::vector &vertices, const std::vect cgalMesh = nullptr; } else { if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) { - if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) { - m_isSelfIntersected = true; - if (removeSelfIntersects) { - if (!CGAL::Polygon_mesh_processing::remove_self_intersections(*cgalMesh)) { - qDebug() << "Mesh remove_self_intersections failed"; - delete cgalMesh; - cgalMesh = nullptr; - } - } else { + if (!disableSelfIntersects) { + if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) { + m_isSelfIntersected = true; qDebug() << "Mesh does_self_intersect"; delete cgalMesh; cgalMesh = nullptr; diff --git a/src/meshcombiner.h b/src/meshcombiner.h index 90ce7337..4801a263 100644 --- a/src/meshcombiner.h +++ b/src/meshcombiner.h @@ -23,7 +23,7 @@ public: { public: Mesh() = default; - Mesh(const std::vector &vertices, const std::vector> &faces, bool removeSelfIntersects=true); + Mesh(const std::vector &vertices, const std::vector> &faces, bool disableSelfIntersects=true); Mesh(const Mesh &other); ~Mesh(); void fetch(std::vector &vertices, std::vector> &faces) const; diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index a926d74c..0507a8f3 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -838,6 +838,13 @@ CombineMode MeshGenerator::componentCombineMode(const std::map return combineMode; } +bool MeshGenerator::componentRemeshed(const std::map *component) +{ + if (nullptr == component) + return false; + return isTrueValueString(valueOfKeyInMapOrEmpty(*component, "remeshed")); +} + QString MeshGenerator::componentColorName(const std::map *component) { if (nullptr == component) @@ -1019,6 +1026,44 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component mesh = nullptr; } + if (nullptr != mesh) { + bool remeshed = componentId.isNull() ? componentRemeshed(&m_snapshot->canvas) : componentRemeshed(component); + if (remeshed) { + std::vector combinedVertices; + std::vector> combinedFaces; + mesh->fetch(combinedVertices, combinedFaces); + std::vector newVertices; + std::vector> newQuads; + std::vector> newTriangles; + remesh(componentCache.outcomeNodes, + combinedVertices, + combinedFaces, + &newVertices, + &newQuads, + &newTriangles, + &componentCache.outcomeNodeVertices); + componentCache.sharedQuadEdges.clear(); + for (const auto &face: newQuads) { + if (face.size() != 4) + continue; + componentCache.sharedQuadEdges.insert({ + PositionKey(newVertices[face[0]]), + PositionKey(newVertices[face[2]]) + }); + componentCache.sharedQuadEdges.insert({ + PositionKey(newVertices[face[1]]), + PositionKey(newVertices[face[3]]) + }); + } + delete mesh; + mesh = new MeshCombiner::Mesh(newVertices, newTriangles, componentId.isNull()); + if (nullptr != mesh) { + delete componentCache.mesh; + componentCache.mesh = new MeshCombiner::Mesh(*mesh); + } + } + } + return mesh; } @@ -1280,6 +1325,8 @@ void MeshGenerator::generate() m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat(); m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat(); + bool remeshed = componentRemeshed(&m_snapshot->canvas); + CombineMode combineMode; auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode); @@ -1290,44 +1337,43 @@ void MeshGenerator::generate() if (nullptr != combinedMesh) { combinedMesh->fetch(combinedVertices, combinedFaces); - size_t totalAffectedNum = 0; - size_t affectedNum = 0; - do { - std::vector weldedVertices; - std::vector> weldedFaces; - affectedNum = weldSeam(combinedVertices, combinedFaces, - 0.025, componentCache.noneSeamVertices, - weldedVertices, weldedFaces); - combinedVertices = weldedVertices; - combinedFaces = weldedFaces; - totalAffectedNum += affectedNum; - } while (affectedNum > 0); - qDebug() << "Total weld affected triangles:" << totalAffectedNum; + if (!remeshed) { + size_t totalAffectedNum = 0; + size_t affectedNum = 0; + do { + std::vector weldedVertices; + std::vector> weldedFaces; + affectedNum = weldSeam(combinedVertices, combinedFaces, + 0.025, componentCache.noneSeamVertices, + weldedVertices, weldedFaces); + combinedVertices = weldedVertices; + combinedFaces = weldedFaces; + totalAffectedNum += affectedNum; + } while (affectedNum > 0); + qDebug() << "Total weld affected triangles:" << totalAffectedNum; + } - recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads); - m_outcome->nodes = componentCache.outcomeNodes; - m_outcome->nodeVertices = componentCache.outcomeNodeVertices; - m_outcome->vertices = combinedVertices; - m_outcome->triangles = combinedFaces; m_outcome->paintMaps = componentCache.outcomePaintMaps; + recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads); + m_outcome->nodeVertices = componentCache.outcomeNodeVertices; + m_outcome->vertices = combinedVertices; + m_outcome->triangles = combinedFaces; /* - Remesher remesher; - remesher.setMesh(combinedVertices, combinedFaces); - remesher.remesh(); - m_outcome->vertices = remesher.getRemeshedVertices(); - const auto &remeshedFaces = remesher.getRemeshedFaces(); - m_outcome->triangleAndQuads = remeshedFaces; - m_outcome->triangles.clear(); - m_outcome->triangles.reserve(remeshedFaces.size() * 2); - for (const auto &it: remeshedFaces) { - m_outcome->triangles.push_back(std::vector { - it[0], it[1], it[2] - }); - m_outcome->triangles.push_back(std::vector { - it[2], it[3], it[0] - }); + if (remeshed) { + remesh(componentCache.outcomeNodes, + combinedVertices, + combinedFaces, + &m_outcome->vertices, + &m_outcome->triangleAndQuads, + &m_outcome->triangles, + &m_outcome->nodeVertices); + } else { + recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads); + m_outcome->nodeVertices = componentCache.outcomeNodeVertices; + m_outcome->vertices = combinedVertices; + m_outcome->triangles = combinedFaces; } */ } @@ -1411,6 +1457,50 @@ void MeshGenerator::generate() qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds"; } +void MeshGenerator::remesh(const std::vector &inputNodes, + const std::vector &inputVertices, + const std::vector> &inputFaces, + std::vector *outputVertices, + std::vector> *outputQuads, + std::vector> *outputTriangles, + std::vector>> *outputNodeVertices) +{ + std::vector> nodes; + std::vector> sourceIds; + nodes.reserve(inputNodes.size()); + sourceIds.reserve(inputNodes.size()); + for (const auto &it: inputNodes) { + nodes.push_back(std::make_pair(it.origin, it.radius)); + sourceIds.push_back(std::make_pair(it.partId, it.nodeId)); + } + Remesher remesher; + remesher.setMesh(inputVertices, inputFaces); + remesher.setNodes(nodes, sourceIds); + remesher.remesh(); + *outputVertices = remesher.getRemeshedVertices(); + const auto &remeshedFaces = remesher.getRemeshedFaces(); + *outputQuads = remeshedFaces; + outputTriangles->clear(); + outputTriangles->reserve(remeshedFaces.size() * 2); + for (const auto &it: remeshedFaces) { + outputTriangles->push_back(std::vector { + it[0], it[1], it[2] + }); + outputTriangles->push_back(std::vector { + it[2], it[3], it[0] + }); + } + const auto &remeshedVertexSources = remesher.getRemeshedVertexSources(); + outputNodeVertices->clear(); + outputNodeVertices->reserve(outputVertices->size()); + for (size_t i = 0; i < outputVertices->size(); ++i) { + const auto &vertexSource = remeshedVertexSources[i]; + if (vertexSource.first.isNull()) + continue; + outputNodeVertices->push_back(std::make_pair((*outputVertices)[i], vertexSource)); + } +} + void MeshGenerator::collectUncombinedComponent(const QString &componentIdString) { const auto &component = findComponent(componentIdString); diff --git a/src/meshgenerator.h b/src/meshgenerator.h index faeda1fe..05fb1906 100644 --- a/src/meshgenerator.h +++ b/src/meshgenerator.h @@ -120,12 +120,20 @@ private: std::vector> *triangleVertexNormals); const std::map *findComponent(const QString &componentIdString); CombineMode componentCombineMode(const std::map *component); + bool componentRemeshed(const std::map *component); MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector &componentIdStrings, GeneratedComponent &componentCache); MeshCombiner::Mesh *combineMultipleMeshes(const std::vector> &multipleMeshes, bool recombine=true); QString componentColorName(const std::map *component); void collectUncombinedComponent(const QString &componentIdString); void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector &cutTemplate); + void remesh(const std::vector &inputNodes, + const std::vector &inputVertices, + const std::vector> &inputFaces, + std::vector *outputVertices, + std::vector> *outputQuads, + std::vector> *outputTriangles, + std::vector>> *outputNodeVertices); }; #endif diff --git a/src/parttreewidget.cpp b/src/parttreewidget.cpp index 95eebcbb..2bd0b7c8 100644 --- a/src/parttreewidget.cpp +++ b/src/parttreewidget.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "parttreewidget.h" #include "partwidget.h" #include "skeletongraphicswidget.h" @@ -31,8 +32,6 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) : setColumnCount(1); setHeaderHidden(true); - m_componentItemMap[QUuid()] = invisibleRootItem(); - setContextMenuPolicy(Qt::CustomContextMenu); //setIconSize(QSize(Theme::miniIconFontSize, Theme::miniIconFontSize)); @@ -61,6 +60,17 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) : gradient.setColorAt(1, Qt::transparent); m_hightlightedPartBackground = QBrush(gradient); + QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(tr("Root"))); + invisibleRootItem()->addChild(item); + item->setData(0, Qt::UserRole, QVariant(QUuid().toString())); + item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); + item->setExpanded(true); + item->setFlags((item->flags() | Qt::ItemIsEnabled) & ~(Qt::ItemIsSelectable)); + m_rootItem = item; + m_componentItemMap[QUuid()] = item; + m_firstSelect = true; + selectComponent(QUuid()); + connect(this, &QTreeWidget::customContextMenuRequested, this, &PartTreeWidget::showContextMenu); connect(this, &QTreeWidget::itemChanged, this, &PartTreeWidget::groupChanged); connect(this, &QTreeWidget::itemExpanded, this, &PartTreeWidget::groupExpanded); @@ -69,6 +79,11 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) : void PartTreeWidget::selectComponent(QUuid componentId, bool multiple) { + if (m_firstSelect) { + m_firstSelect = false; + updateComponentSelectState(QUuid(), true); + return; + } if (multiple) { if (!m_currentSelectedComponentId.isNull()) { m_selectedComponentIds.insert(m_currentSelectedComponentId); @@ -97,13 +112,13 @@ void PartTreeWidget::selectComponent(QUuid componentId, bool multiple) m_selectedComponentIds.clear(); } if (m_currentSelectedComponentId != componentId) { - if (!m_currentSelectedComponentId.isNull()) { + //if (!m_currentSelectedComponentId.isNull()) { updateComponentSelectState(m_currentSelectedComponentId, false); - } + //} m_currentSelectedComponentId = componentId; - if (!m_currentSelectedComponentId.isNull()) { + //if (!m_currentSelectedComponentId.isNull()) { updateComponentSelectState(m_currentSelectedComponentId, true); - } + //} emit currentComponentChanged(m_currentSelectedComponentId); } } @@ -269,9 +284,30 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) previewLabel->setText(component->name); } else if (!componentIds.empty()) { previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size()))); + } else { + previewLabel->hide(); } layout->addWidget(previewLabel); } + QCheckBox *remeshBox = nullptr; + if (componentIds.size() <= 1) { + remeshBox = new QCheckBox(); + remeshBox->setText(tr("Remeshed")); + if (nullptr == component) { + if (m_document->remeshed) + remeshBox->setChecked(true); + connect(remeshBox, &QCheckBox::stateChanged, this, [=]() { + emit setComponentRemeshState(QUuid(), remeshBox->isChecked()); + }); + } else { + if (component->remeshed) + remeshBox->setChecked(true); + connect(remeshBox, &QCheckBox::stateChanged, this, [=]() { + emit setComponentRemeshState(component->id, remeshBox->isChecked()); + }); + } + Theme::initCheckbox(remeshBox); + } QWidget *widget = new QWidget; if (nullptr != component) { QComboBox *combineModeSelectBox = new QComboBox; @@ -325,16 +361,22 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) QVBoxLayout *newLayout = new QVBoxLayout; newLayout->addLayout(layout); + if (nullptr != remeshBox) + newLayout->addWidget(remeshBox); newLayout->addLayout(componentSettingsLayout); widget->setLayout(newLayout); } else { - widget->setLayout(layout); + QVBoxLayout *newLayout = new QVBoxLayout; + newLayout->addLayout(layout); + if (nullptr != remeshBox) + newLayout->addWidget(remeshBox); + widget->setLayout(newLayout); } forDisplayPartImage.setDefaultWidget(widget); - if (!componentIds.empty()) { + //if (!componentIds.empty()) { contextMenu.addAction(&forDisplayPartImage); contextMenu.addSeparator(); - } + //} QAction showAction(tr("Show"), this); showAction.setIcon(Theme::awesome()->icon(fa::eye)); @@ -456,12 +498,14 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) QAction collapseAllAction(tr("Collapse All"), this); connect(&collapseAllAction, &QAction::triggered, [=]() { + m_rootItem->setExpanded(false); emit collapseAllComponents(); }); contextMenu.addAction(&collapseAllAction); QAction expandAllAction(tr("Expand All"), this); connect(&expandAllAction, &QAction::triggered, [=]() { + m_rootItem->setExpanded(true); emit expandAllComponents(); }); contextMenu.addAction(&expandAllAction); @@ -810,9 +854,9 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId) addComponentChildrenToItem(componentId, parentItem); // Fix the last item show in the wrong place sometimes - int childCount = invisibleRootItem()->childCount(); + int childCount = m_rootItem->childCount(); if (childCount > 0) { - QTreeWidgetItem *lastItem = invisibleRootItem()->child(childCount - 1); + QTreeWidgetItem *lastItem = m_rootItem->child(childCount - 1); bool isExpanded = lastItem->isExpanded(); lastItem->setExpanded(!isExpanded); lastItem->setExpanded(isExpanded); @@ -821,10 +865,10 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId) void PartTreeWidget::removeAllContent() { - qDeleteAll(invisibleRootItem()->takeChildren()); + qDeleteAll(m_rootItem->takeChildren()); m_partItemMap.clear(); m_componentItemMap.clear(); - m_componentItemMap[QUuid()] = invisibleRootItem(); + m_componentItemMap[QUuid()] = m_rootItem; } void PartTreeWidget::componentRemoved(QUuid componentId) diff --git a/src/parttreewidget.h b/src/parttreewidget.h index 3e89cd56..da0e43aa 100644 --- a/src/parttreewidget.h +++ b/src/parttreewidget.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "document.h" class PartTreeWidget : public QTreeWidget @@ -21,6 +22,7 @@ signals: void setComponentExpandState(QUuid componentId, bool expanded); void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); + void setComponentRemeshState(QUuid componentId, bool remeshed); void setPartTarget(QUuid partId, PartTarget target); void setPartBase(QUuid partId, PartBase base); void moveComponent(QUuid componentId, QUuid toParentId); @@ -93,6 +95,8 @@ private: bool isComponentSelected(QUuid componentId); private: const Document *m_document = nullptr; + QTreeWidgetItem *m_rootItem = nullptr; + bool m_firstSelect = true; std::map m_partItemMap; std::map m_componentItemMap; QFont m_normalFont; diff --git a/src/remesher.cpp b/src/remesher.cpp index a71aba4a..84e5feb1 100644 --- a/src/remesher.cpp +++ b/src/remesher.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef WITH_CUDA #include #endif @@ -20,15 +21,21 @@ void Remesher::setMesh(const std::vector &vertices, m_triangles = triangles; } -const std::vector &Remesher::getRemeshedVertices() +const std::vector &Remesher::getRemeshedVertices() const { return m_remeshedVertices; } -const std::vector> &Remesher::getRemeshedFaces() + +const std::vector> &Remesher::getRemeshedFaces() const { return m_remeshedFaces; } +const std::vector> &Remesher::getRemeshedVertexSources() const +{ + return m_remeshedVertexSources; +} + void Remesher::remesh() { Parametrizer field; @@ -104,6 +111,39 @@ void Remesher::remesh() }); } - printf("m_remeshedVertices.size:%lu\r\n", m_remeshedVertices.size()); - printf("m_remeshedFaces.size:%lu\r\n", m_remeshedFaces.size()); + resolveSources(); +} + +void Remesher::setNodes(const std::vector> &nodes, + const std::vector> &sourceIds) +{ + m_nodes = nodes; + m_sourceIds = sourceIds; +} + +void Remesher::resolveSources() +{ + m_remeshedVertexSources.resize(m_remeshedVertices.size()); + std::vector nodeRadius2(m_nodes.size()); + for (size_t nodeIndex = 0; nodeIndex < m_nodes.size(); ++nodeIndex) { + nodeRadius2[nodeIndex] = std::pow(m_nodes[nodeIndex].second, 2); + } + for (size_t vertexIndex = 0; vertexIndex < m_remeshedVertices.size(); ++vertexIndex) { + std::vector> matches; + const auto &vertexPosition = m_remeshedVertices[vertexIndex]; + for (size_t nodeIndex = 0; nodeIndex < m_nodes.size(); ++nodeIndex) { + const auto &nodePosition = m_nodes[nodeIndex].first; + auto length2 = (vertexPosition - nodePosition).lengthSquared(); + if (length2 > nodeRadius2[nodeIndex]) + continue; + matches.push_back(std::make_pair(length2, nodeIndex)); + } + std::sort(matches.begin(), matches.end(), [](const std::pair &first, + const std::pair &second) { + return first.first < second.first; + }); + if (matches.empty()) + continue; + m_remeshedVertexSources[vertexIndex] = m_sourceIds[matches[0].second]; + } } diff --git a/src/remesher.h b/src/remesher.h index 1a35515f..7aa3a720 100644 --- a/src/remesher.h +++ b/src/remesher.h @@ -3,6 +3,7 @@ #include #include #include +#include class Remesher : public QObject { @@ -11,14 +12,21 @@ public: ~Remesher(); void setMesh(const std::vector &vertices, const std::vector> &triangles); + void setNodes(const std::vector> &nodes, + const std::vector> &sourceIds); void remesh(); - const std::vector &getRemeshedVertices(); - const std::vector> &getRemeshedFaces(); + const std::vector &getRemeshedVertices() const; + const std::vector> &getRemeshedFaces() const; + const std::vector> &getRemeshedVertexSources() const; private: std::vector m_vertices; std::vector> m_triangles; std::vector m_remeshedVertices; std::vector> m_remeshedFaces; + std::vector> m_remeshedVertexSources; + std::vector> m_nodes; + std::vector> m_sourceIds; + void resolveSources(); }; #endif diff --git a/src/theme.cpp b/src/theme.cpp index 919d7193..fd61dbac 100644 --- a/src/theme.cpp +++ b/src/theme.cpp @@ -56,7 +56,7 @@ void Theme::initAwsomeBaseSizes() Theme::miniIconFontSize = (int)(Theme::toolIconFontSize * 0.7); Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67); Theme::partPreviewImageSize = (Theme::miniIconSize * 3); - Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 3.7; + Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 4; //3.7; Theme::posePreviewImageSize = Theme::sidebarPreferredWidth * 0.4; Theme::materialPreviewImageSize = Theme::posePreviewImageSize; Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize;