Implement component remesh

master
Jeremy Hu 2019-12-29 18:22:35 +09:30
parent 6875bee519
commit 191dbacd89
13 changed files with 291 additions and 64 deletions

View File

@ -736,6 +736,10 @@ Tips:
<source>Paste Color</source> <source>Paste Color</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Remeshed</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>PartWidget</name> <name>PartWidget</name>

View File

@ -37,6 +37,7 @@ Document::Document() :
textureAmbientOcclusionImage(nullptr), textureAmbientOcclusionImage(nullptr),
rigType(RigType::None), rigType(RigType::None),
weldEnabled(true), weldEnabled(true),
remeshed(false),
// private // private
m_isResultMeshObsolete(false), m_isResultMeshObsolete(false),
m_meshGenerator(nullptr), m_meshGenerator(nullptr),
@ -1201,6 +1202,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
component["smoothAll"] = QString::number(componentIt.second.smoothAll); component["smoothAll"] = QString::number(componentIt.second.smoothAll);
if (componentIt.second.smoothSeamAdjusted()) if (componentIt.second.smoothSeamAdjusted())
component["smoothSeam"] = QString::number(componentIt.second.smoothSeam); component["smoothSeam"] = QString::number(componentIt.second.smoothSeam);
if (componentIt.second.remeshed)
component["remeshed"] = "true";
QStringList childIdList; QStringList childIdList;
for (const auto &childId: componentIt.second.childrenIds) { for (const auto &childId: componentIt.second.childrenIds) {
childIdList.append(childId.toString()); childIdList.append(childId.toString());
@ -1315,6 +1318,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
canvas["originY"] = QString::number(getOriginY()); canvas["originY"] = QString::number(getOriginY());
canvas["originZ"] = QString::number(getOriginZ()); canvas["originZ"] = QString::number(getOriginZ());
canvas["rigType"] = RigTypeToString(rigType); canvas["rigType"] = RigTypeToString(rigType);
if (this->remeshed)
canvas["remeshed"] = "true";
snapshot->canvas = canvas; snapshot->canvas = canvas;
} }
} }
@ -1472,6 +1477,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
bool isOriginChanged = false; bool isOriginChanged = false;
bool isRigTypeChanged = false; bool isRigTypeChanged = false;
if (!fromPaste) { if (!fromPaste) {
this->remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(snapshot.canvas, "remeshed"));
const auto &originXit = snapshot.canvas.find("originX"); const auto &originXit = snapshot.canvas.find("originX");
const auto &originYit = snapshot.canvas.find("originY"); const auto &originYit = snapshot.canvas.find("originY");
const auto &originZit = snapshot.canvas.find("originZ"); 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"); const auto &smoothSeamIt = componentKv.second.find("smoothSeam");
if (smoothSeamIt != componentKv.second.end()) if (smoothSeamIt != componentKv.second.end())
component.setSmoothSeam(smoothSeamIt->second.toFloat()); component.setSmoothSeam(smoothSeamIt->second.toFloat());
component.remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "remeshed"));
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name; //qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
if ("partId" == linkDataType) { if ("partId" == linkDataType) {
QUuid partId = oldNewIdMap[QUuid(linkData)]; QUuid partId = oldNewIdMap[QUuid(linkData)];
@ -2488,6 +2495,29 @@ void Document::setComponentExpandState(QUuid componentId, bool expanded)
emit optionsChanged(); 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) void Document::createNewComponentAndMoveThisIn(QUuid componentId)
{ {
auto component = componentMap.find(componentId); auto component = componentMap.find(componentId);

View File

@ -66,6 +66,7 @@ public:
bool dirty = true; bool dirty = true;
float smoothAll = 0.0; float smoothAll = 0.0;
float smoothSeam = 0.0; float smoothSeam = 0.0;
bool remeshed = false;
std::vector<QUuid> childrenIds; std::vector<QUuid> childrenIds;
QString linkData() const QString linkData() const
{ {
@ -394,6 +395,7 @@ signals:
void componentExpandStateChanged(QUuid componentId); void componentExpandStateChanged(QUuid componentId);
void componentSmoothAllChanged(QUuid componentId); void componentSmoothAllChanged(QUuid componentId);
void componentSmoothSeamChanged(QUuid componentId); void componentSmoothSeamChanged(QUuid componentId);
void componentRemeshStateChanged(QUuid componentId);
void nodeRemoved(QUuid nodeId); void nodeRemoved(QUuid nodeId);
void edgeRemoved(QUuid edgeId); void edgeRemoved(QUuid edgeId);
void nodeRadiusChanged(QUuid nodeId); void nodeRadiusChanged(QUuid nodeId);
@ -503,6 +505,7 @@ public: // need initialize
QImage *textureAmbientOcclusionImage; QImage *textureAmbientOcclusionImage;
RigType rigType; RigType rigType;
bool weldEnabled; bool weldEnabled;
bool remeshed;
public: public:
Document(); Document();
~Document(); ~Document();
@ -647,6 +650,7 @@ public slots:
void setComponentExpandState(QUuid componentId, bool expanded); void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentRemeshState(QUuid componentId, bool remeshed);
void hideOtherComponents(QUuid componentId); void hideOtherComponents(QUuid componentId);
void lockOtherComponents(QUuid componentId); void lockOtherComponents(QUuid componentId);
void hideAllComponents(); void hideAllComponents();

View File

@ -997,6 +997,7 @@ DocumentWindow::DocumentWindow() :
connect(partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState); connect(partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState);
connect(partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll); connect(partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll);
connect(partTreeWidget, &PartTreeWidget::setComponentSmoothSeam, m_document, &Document::setComponentSmoothSeam); 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::moveComponent, m_document, &Document::moveComponent);
connect(partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent); connect(partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent);
connect(partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents); connect(partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents);

View File

@ -10,7 +10,7 @@
typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel;
typedef CGAL::Surface_mesh<CgalKernel::Point_3> CgalMesh; typedef CGAL::Surface_mesh<CgalKernel::Point_3> CgalMesh;
MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool removeSelfIntersects) MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects)
{ {
CgalMesh *cgalMesh = nullptr; CgalMesh *cgalMesh = nullptr;
if (!faces.empty()) { if (!faces.empty()) {
@ -21,15 +21,9 @@ MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vect
cgalMesh = nullptr; cgalMesh = nullptr;
} else { } else {
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) { if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
if (!disableSelfIntersects) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) { if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true; 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 {
qDebug() << "Mesh does_self_intersect"; qDebug() << "Mesh does_self_intersect";
delete cgalMesh; delete cgalMesh;
cgalMesh = nullptr; cgalMesh = nullptr;

View File

@ -23,7 +23,7 @@ public:
{ {
public: public:
Mesh() = default; Mesh() = default;
Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool removeSelfIntersects=true); Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects=true);
Mesh(const Mesh &other); Mesh(const Mesh &other);
~Mesh(); ~Mesh();
void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const; void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const;

View File

@ -838,6 +838,13 @@ CombineMode MeshGenerator::componentCombineMode(const std::map<QString, QString>
return combineMode; return combineMode;
} }
bool MeshGenerator::componentRemeshed(const std::map<QString, QString> *component)
{
if (nullptr == component)
return false;
return isTrueValueString(valueOfKeyInMapOrEmpty(*component, "remeshed"));
}
QString MeshGenerator::componentColorName(const std::map<QString, QString> *component) QString MeshGenerator::componentColorName(const std::map<QString, QString> *component)
{ {
if (nullptr == component) if (nullptr == component)
@ -1019,6 +1026,44 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
mesh = nullptr; mesh = nullptr;
} }
if (nullptr != mesh) {
bool remeshed = componentId.isNull() ? componentRemeshed(&m_snapshot->canvas) : componentRemeshed(component);
if (remeshed) {
std::vector<QVector3D> combinedVertices;
std::vector<std::vector<size_t>> combinedFaces;
mesh->fetch(combinedVertices, combinedFaces);
std::vector<QVector3D> newVertices;
std::vector<std::vector<size_t>> newQuads;
std::vector<std::vector<size_t>> 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; return mesh;
} }
@ -1280,6 +1325,8 @@ void MeshGenerator::generate()
m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat(); m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat(); m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
bool remeshed = componentRemeshed(&m_snapshot->canvas);
CombineMode combineMode; CombineMode combineMode;
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode); auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
@ -1290,6 +1337,7 @@ void MeshGenerator::generate()
if (nullptr != combinedMesh) { if (nullptr != combinedMesh) {
combinedMesh->fetch(combinedVertices, combinedFaces); combinedMesh->fetch(combinedVertices, combinedFaces);
if (!remeshed) {
size_t totalAffectedNum = 0; size_t totalAffectedNum = 0;
size_t affectedNum = 0; size_t affectedNum = 0;
do { do {
@ -1303,31 +1351,29 @@ void MeshGenerator::generate()
totalAffectedNum += affectedNum; totalAffectedNum += affectedNum;
} while (affectedNum > 0); } while (affectedNum > 0);
qDebug() << "Total weld affected triangles:" << totalAffectedNum; qDebug() << "Total weld affected triangles:" << totalAffectedNum;
}
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
m_outcome->nodes = componentCache.outcomeNodes; m_outcome->nodes = componentCache.outcomeNodes;
m_outcome->paintMaps = componentCache.outcomePaintMaps;
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
m_outcome->nodeVertices = componentCache.outcomeNodeVertices; m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
m_outcome->vertices = combinedVertices; m_outcome->vertices = combinedVertices;
m_outcome->triangles = combinedFaces; m_outcome->triangles = combinedFaces;
m_outcome->paintMaps = componentCache.outcomePaintMaps;
/* /*
Remesher remesher; if (remeshed) {
remesher.setMesh(combinedVertices, combinedFaces); remesh(componentCache.outcomeNodes,
remesher.remesh(); combinedVertices,
m_outcome->vertices = remesher.getRemeshedVertices(); combinedFaces,
const auto &remeshedFaces = remesher.getRemeshedFaces(); &m_outcome->vertices,
m_outcome->triangleAndQuads = remeshedFaces; &m_outcome->triangleAndQuads,
m_outcome->triangles.clear(); &m_outcome->triangles,
m_outcome->triangles.reserve(remeshedFaces.size() * 2); &m_outcome->nodeVertices);
for (const auto &it: remeshedFaces) { } else {
m_outcome->triangles.push_back(std::vector<size_t> { recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
it[0], it[1], it[2] m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
}); m_outcome->vertices = combinedVertices;
m_outcome->triangles.push_back(std::vector<size_t> { m_outcome->triangles = combinedFaces;
it[2], it[3], it[0]
});
} }
*/ */
} }
@ -1411,6 +1457,50 @@ void MeshGenerator::generate()
qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds"; qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
} }
void MeshGenerator::remesh(const std::vector<OutcomeNode> &inputNodes,
const std::vector<QVector3D> &inputVertices,
const std::vector<std::vector<size_t>> &inputFaces,
std::vector<QVector3D> *outputVertices,
std::vector<std::vector<size_t>> *outputQuads,
std::vector<std::vector<size_t>> *outputTriangles,
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices)
{
std::vector<std::pair<QVector3D, float>> nodes;
std::vector<std::pair<QUuid, QUuid>> 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<size_t> {
it[0], it[1], it[2]
});
outputTriangles->push_back(std::vector<size_t> {
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) void MeshGenerator::collectUncombinedComponent(const QString &componentIdString)
{ {
const auto &component = findComponent(componentIdString); const auto &component = findComponent(componentIdString);

View File

@ -120,12 +120,20 @@ private:
std::vector<std::vector<QVector3D>> *triangleVertexNormals); std::vector<std::vector<QVector3D>> *triangleVertexNormals);
const std::map<QString, QString> *findComponent(const QString &componentIdString); const std::map<QString, QString> *findComponent(const QString &componentIdString);
CombineMode componentCombineMode(const std::map<QString, QString> *component); CombineMode componentCombineMode(const std::map<QString, QString> *component);
bool componentRemeshed(const std::map<QString, QString> *component);
MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings, MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
GeneratedComponent &componentCache); GeneratedComponent &componentCache);
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true); MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
QString componentColorName(const std::map<QString, QString> *component); QString componentColorName(const std::map<QString, QString> *component);
void collectUncombinedComponent(const QString &componentIdString); void collectUncombinedComponent(const QString &componentIdString);
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate); void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
void remesh(const std::vector<OutcomeNode> &inputNodes,
const std::vector<QVector3D> &inputVertices,
const std::vector<std::vector<size_t>> &inputFaces,
std::vector<QVector3D> *outputVertices,
std::vector<std::vector<size_t>> *outputQuads,
std::vector<std::vector<size_t>> *outputTriangles,
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices);
}; };
#endif #endif

View File

@ -11,6 +11,7 @@
#include <QClipboard> #include <QClipboard>
#include <QMimeData> #include <QMimeData>
#include <QApplication> #include <QApplication>
#include <QCheckBox>
#include "parttreewidget.h" #include "parttreewidget.h"
#include "partwidget.h" #include "partwidget.h"
#include "skeletongraphicswidget.h" #include "skeletongraphicswidget.h"
@ -31,8 +32,6 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) :
setColumnCount(1); setColumnCount(1);
setHeaderHidden(true); setHeaderHidden(true);
m_componentItemMap[QUuid()] = invisibleRootItem();
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
//setIconSize(QSize(Theme::miniIconFontSize, Theme::miniIconFontSize)); //setIconSize(QSize(Theme::miniIconFontSize, Theme::miniIconFontSize));
@ -61,6 +60,17 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) :
gradient.setColorAt(1, Qt::transparent); gradient.setColorAt(1, Qt::transparent);
m_hightlightedPartBackground = QBrush(gradient); 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::customContextMenuRequested, this, &PartTreeWidget::showContextMenu);
connect(this, &QTreeWidget::itemChanged, this, &PartTreeWidget::groupChanged); connect(this, &QTreeWidget::itemChanged, this, &PartTreeWidget::groupChanged);
connect(this, &QTreeWidget::itemExpanded, this, &PartTreeWidget::groupExpanded); 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) void PartTreeWidget::selectComponent(QUuid componentId, bool multiple)
{ {
if (m_firstSelect) {
m_firstSelect = false;
updateComponentSelectState(QUuid(), true);
return;
}
if (multiple) { if (multiple) {
if (!m_currentSelectedComponentId.isNull()) { if (!m_currentSelectedComponentId.isNull()) {
m_selectedComponentIds.insert(m_currentSelectedComponentId); m_selectedComponentIds.insert(m_currentSelectedComponentId);
@ -97,13 +112,13 @@ void PartTreeWidget::selectComponent(QUuid componentId, bool multiple)
m_selectedComponentIds.clear(); m_selectedComponentIds.clear();
} }
if (m_currentSelectedComponentId != componentId) { if (m_currentSelectedComponentId != componentId) {
if (!m_currentSelectedComponentId.isNull()) { //if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, false); updateComponentSelectState(m_currentSelectedComponentId, false);
} //}
m_currentSelectedComponentId = componentId; m_currentSelectedComponentId = componentId;
if (!m_currentSelectedComponentId.isNull()) { //if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, true); updateComponentSelectState(m_currentSelectedComponentId, true);
} //}
emit currentComponentChanged(m_currentSelectedComponentId); emit currentComponentChanged(m_currentSelectedComponentId);
} }
} }
@ -269,9 +284,30 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
previewLabel->setText(component->name); previewLabel->setText(component->name);
} else if (!componentIds.empty()) { } else if (!componentIds.empty()) {
previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size()))); previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size())));
} else {
previewLabel->hide();
} }
layout->addWidget(previewLabel); 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; QWidget *widget = new QWidget;
if (nullptr != component) { if (nullptr != component) {
QComboBox *combineModeSelectBox = new QComboBox; QComboBox *combineModeSelectBox = new QComboBox;
@ -325,16 +361,22 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
QVBoxLayout *newLayout = new QVBoxLayout; QVBoxLayout *newLayout = new QVBoxLayout;
newLayout->addLayout(layout); newLayout->addLayout(layout);
if (nullptr != remeshBox)
newLayout->addWidget(remeshBox);
newLayout->addLayout(componentSettingsLayout); newLayout->addLayout(componentSettingsLayout);
widget->setLayout(newLayout); widget->setLayout(newLayout);
} else { } else {
widget->setLayout(layout); QVBoxLayout *newLayout = new QVBoxLayout;
newLayout->addLayout(layout);
if (nullptr != remeshBox)
newLayout->addWidget(remeshBox);
widget->setLayout(newLayout);
} }
forDisplayPartImage.setDefaultWidget(widget); forDisplayPartImage.setDefaultWidget(widget);
if (!componentIds.empty()) { //if (!componentIds.empty()) {
contextMenu.addAction(&forDisplayPartImage); contextMenu.addAction(&forDisplayPartImage);
contextMenu.addSeparator(); contextMenu.addSeparator();
} //}
QAction showAction(tr("Show"), this); QAction showAction(tr("Show"), this);
showAction.setIcon(Theme::awesome()->icon(fa::eye)); showAction.setIcon(Theme::awesome()->icon(fa::eye));
@ -456,12 +498,14 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
QAction collapseAllAction(tr("Collapse All"), this); QAction collapseAllAction(tr("Collapse All"), this);
connect(&collapseAllAction, &QAction::triggered, [=]() { connect(&collapseAllAction, &QAction::triggered, [=]() {
m_rootItem->setExpanded(false);
emit collapseAllComponents(); emit collapseAllComponents();
}); });
contextMenu.addAction(&collapseAllAction); contextMenu.addAction(&collapseAllAction);
QAction expandAllAction(tr("Expand All"), this); QAction expandAllAction(tr("Expand All"), this);
connect(&expandAllAction, &QAction::triggered, [=]() { connect(&expandAllAction, &QAction::triggered, [=]() {
m_rootItem->setExpanded(true);
emit expandAllComponents(); emit expandAllComponents();
}); });
contextMenu.addAction(&expandAllAction); contextMenu.addAction(&expandAllAction);
@ -810,9 +854,9 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId)
addComponentChildrenToItem(componentId, parentItem); addComponentChildrenToItem(componentId, parentItem);
// Fix the last item show in the wrong place sometimes // Fix the last item show in the wrong place sometimes
int childCount = invisibleRootItem()->childCount(); int childCount = m_rootItem->childCount();
if (childCount > 0) { if (childCount > 0) {
QTreeWidgetItem *lastItem = invisibleRootItem()->child(childCount - 1); QTreeWidgetItem *lastItem = m_rootItem->child(childCount - 1);
bool isExpanded = lastItem->isExpanded(); bool isExpanded = lastItem->isExpanded();
lastItem->setExpanded(!isExpanded); lastItem->setExpanded(!isExpanded);
lastItem->setExpanded(isExpanded); lastItem->setExpanded(isExpanded);
@ -821,10 +865,10 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId)
void PartTreeWidget::removeAllContent() void PartTreeWidget::removeAllContent()
{ {
qDeleteAll(invisibleRootItem()->takeChildren()); qDeleteAll(m_rootItem->takeChildren());
m_partItemMap.clear(); m_partItemMap.clear();
m_componentItemMap.clear(); m_componentItemMap.clear();
m_componentItemMap[QUuid()] = invisibleRootItem(); m_componentItemMap[QUuid()] = m_rootItem;
} }
void PartTreeWidget::componentRemoved(QUuid componentId) void PartTreeWidget::componentRemoved(QUuid componentId)

View File

@ -3,6 +3,7 @@
#include <QTreeWidget> #include <QTreeWidget>
#include <QUuid> #include <QUuid>
#include <QMouseEvent> #include <QMouseEvent>
#include <QTreeWidgetItem>
#include "document.h" #include "document.h"
class PartTreeWidget : public QTreeWidget class PartTreeWidget : public QTreeWidget
@ -21,6 +22,7 @@ signals:
void setComponentExpandState(QUuid componentId, bool expanded); void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentRemeshState(QUuid componentId, bool remeshed);
void setPartTarget(QUuid partId, PartTarget target); void setPartTarget(QUuid partId, PartTarget target);
void setPartBase(QUuid partId, PartBase base); void setPartBase(QUuid partId, PartBase base);
void moveComponent(QUuid componentId, QUuid toParentId); void moveComponent(QUuid componentId, QUuid toParentId);
@ -93,6 +95,8 @@ private:
bool isComponentSelected(QUuid componentId); bool isComponentSelected(QUuid componentId);
private: private:
const Document *m_document = nullptr; const Document *m_document = nullptr;
QTreeWidgetItem *m_rootItem = nullptr;
bool m_firstSelect = true;
std::map<QUuid, QTreeWidgetItem *> m_partItemMap; std::map<QUuid, QTreeWidgetItem *> m_partItemMap;
std::map<QUuid, QTreeWidgetItem *> m_componentItemMap; std::map<QUuid, QTreeWidgetItem *> m_componentItemMap;
QFont m_normalFont; QFont m_normalFont;

View File

@ -2,6 +2,7 @@
#include <field-math.hpp> #include <field-math.hpp>
#include <optimizer.hpp> #include <optimizer.hpp>
#include <parametrizer.hpp> #include <parametrizer.hpp>
#include <cmath>
#ifdef WITH_CUDA #ifdef WITH_CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
#endif #endif
@ -20,15 +21,21 @@ void Remesher::setMesh(const std::vector<QVector3D> &vertices,
m_triangles = triangles; m_triangles = triangles;
} }
const std::vector<QVector3D> &Remesher::getRemeshedVertices() const std::vector<QVector3D> &Remesher::getRemeshedVertices() const
{ {
return m_remeshedVertices; return m_remeshedVertices;
} }
const std::vector<std::vector<size_t>> &Remesher::getRemeshedFaces()
const std::vector<std::vector<size_t>> &Remesher::getRemeshedFaces() const
{ {
return m_remeshedFaces; return m_remeshedFaces;
} }
const std::vector<std::pair<QUuid, QUuid>> &Remesher::getRemeshedVertexSources() const
{
return m_remeshedVertexSources;
}
void Remesher::remesh() void Remesher::remesh()
{ {
Parametrizer field; Parametrizer field;
@ -104,6 +111,39 @@ void Remesher::remesh()
}); });
} }
printf("m_remeshedVertices.size:%lu\r\n", m_remeshedVertices.size()); resolveSources();
printf("m_remeshedFaces.size:%lu\r\n", m_remeshedFaces.size()); }
void Remesher::setNodes(const std::vector<std::pair<QVector3D, float>> &nodes,
const std::vector<std::pair<QUuid, QUuid>> &sourceIds)
{
m_nodes = nodes;
m_sourceIds = sourceIds;
}
void Remesher::resolveSources()
{
m_remeshedVertexSources.resize(m_remeshedVertices.size());
std::vector<float> 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<std::pair<float, size_t>> 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<float, size_t> &first,
const std::pair<float, size_t> &second) {
return first.first < second.first;
});
if (matches.empty())
continue;
m_remeshedVertexSources[vertexIndex] = m_sourceIds[matches[0].second];
}
} }

View File

@ -3,6 +3,7 @@
#include <QObject> #include <QObject>
#include <vector> #include <vector>
#include <QVector3D> #include <QVector3D>
#include <QUuid>
class Remesher : public QObject class Remesher : public QObject
{ {
@ -11,14 +12,21 @@ public:
~Remesher(); ~Remesher();
void setMesh(const std::vector<QVector3D> &vertices, void setMesh(const std::vector<QVector3D> &vertices,
const std::vector<std::vector<size_t>> &triangles); const std::vector<std::vector<size_t>> &triangles);
void setNodes(const std::vector<std::pair<QVector3D, float>> &nodes,
const std::vector<std::pair<QUuid, QUuid>> &sourceIds);
void remesh(); void remesh();
const std::vector<QVector3D> &getRemeshedVertices(); const std::vector<QVector3D> &getRemeshedVertices() const;
const std::vector<std::vector<size_t>> &getRemeshedFaces(); const std::vector<std::vector<size_t>> &getRemeshedFaces() const;
const std::vector<std::pair<QUuid, QUuid>> &getRemeshedVertexSources() const;
private: private:
std::vector<QVector3D> m_vertices; std::vector<QVector3D> m_vertices;
std::vector<std::vector<size_t>> m_triangles; std::vector<std::vector<size_t>> m_triangles;
std::vector<QVector3D> m_remeshedVertices; std::vector<QVector3D> m_remeshedVertices;
std::vector<std::vector<size_t>> m_remeshedFaces; std::vector<std::vector<size_t>> m_remeshedFaces;
std::vector<std::pair<QUuid, QUuid>> m_remeshedVertexSources;
std::vector<std::pair<QVector3D, float>> m_nodes;
std::vector<std::pair<QUuid, QUuid>> m_sourceIds;
void resolveSources();
}; };
#endif #endif

View File

@ -56,7 +56,7 @@ void Theme::initAwsomeBaseSizes()
Theme::miniIconFontSize = (int)(Theme::toolIconFontSize * 0.7); Theme::miniIconFontSize = (int)(Theme::toolIconFontSize * 0.7);
Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67); Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67);
Theme::partPreviewImageSize = (Theme::miniIconSize * 3); 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::posePreviewImageSize = Theme::sidebarPreferredWidth * 0.4;
Theme::materialPreviewImageSize = Theme::posePreviewImageSize; Theme::materialPreviewImageSize = Theme::posePreviewImageSize;
Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize; Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize;