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:
粘贴颜色
+
+
+ 重新网格化
+
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;