Implement component remesh
parent
6875bee519
commit
191dbacd89
|
@ -736,6 +736,10 @@ Tips:
|
|||
<source>Paste Color</source>
|
||||
<translation>粘贴颜色</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remeshed</source>
|
||||
<translation>重新网格化</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PartWidget</name>
|
||||
|
|
|
@ -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<QUuid> &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<QUuid> &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);
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
bool dirty = true;
|
||||
float smoothAll = 0.0;
|
||||
float smoothSeam = 0.0;
|
||||
bool remeshed = false;
|
||||
std::vector<QUuid> 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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel;
|
||||
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;
|
||||
if (!faces.empty()) {
|
||||
|
@ -21,15 +21,9 @@ MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vect
|
|||
cgalMesh = nullptr;
|
||||
} else {
|
||||
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
|
||||
if (!disableSelfIntersects) {
|
||||
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 {
|
||||
qDebug() << "Mesh does_self_intersect";
|
||||
delete cgalMesh;
|
||||
cgalMesh = nullptr;
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
{
|
||||
public:
|
||||
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();
|
||||
void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const;
|
||||
|
|
|
@ -838,6 +838,13 @@ CombineMode MeshGenerator::componentCombineMode(const std::map<QString, QString>
|
|||
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)
|
||||
{
|
||||
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<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;
|
||||
}
|
||||
|
||||
|
@ -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,6 +1337,7 @@ void MeshGenerator::generate()
|
|||
if (nullptr != combinedMesh) {
|
||||
combinedMesh->fetch(combinedVertices, combinedFaces);
|
||||
|
||||
if (!remeshed) {
|
||||
size_t totalAffectedNum = 0;
|
||||
size_t affectedNum = 0;
|
||||
do {
|
||||
|
@ -1303,31 +1351,29 @@ void MeshGenerator::generate()
|
|||
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->paintMaps = componentCache.outcomePaintMaps;
|
||||
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
|
||||
m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
|
||||
m_outcome->vertices = combinedVertices;
|
||||
m_outcome->triangles = combinedFaces;
|
||||
m_outcome->paintMaps = componentCache.outcomePaintMaps;
|
||||
|
||||
/*
|
||||
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<size_t> {
|
||||
it[0], it[1], it[2]
|
||||
});
|
||||
m_outcome->triangles.push_back(std::vector<size_t> {
|
||||
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<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)
|
||||
{
|
||||
const auto &component = findComponent(componentIdString);
|
||||
|
|
|
@ -120,12 +120,20 @@ private:
|
|||
std::vector<std::vector<QVector3D>> *triangleVertexNormals);
|
||||
const std::map<QString, QString> *findComponent(const QString &componentIdString);
|
||||
CombineMode componentCombineMode(const std::map<QString, QString> *component);
|
||||
bool componentRemeshed(const std::map<QString, QString> *component);
|
||||
MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
|
||||
GeneratedComponent &componentCache);
|
||||
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
|
||||
QString componentColorName(const std::map<QString, QString> *component);
|
||||
void collectUncombinedComponent(const QString &componentIdString);
|
||||
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
|
||||
void 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
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <QClipboard>
|
||||
#include <QMimeData>
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#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)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QTreeWidget>
|
||||
#include <QUuid>
|
||||
#include <QMouseEvent>
|
||||
#include <QTreeWidgetItem>
|
||||
#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<QUuid, QTreeWidgetItem *> m_partItemMap;
|
||||
std::map<QUuid, QTreeWidgetItem *> m_componentItemMap;
|
||||
QFont m_normalFont;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <field-math.hpp>
|
||||
#include <optimizer.hpp>
|
||||
#include <parametrizer.hpp>
|
||||
#include <cmath>
|
||||
#ifdef WITH_CUDA
|
||||
#include <cuda_runtime.h>
|
||||
#endif
|
||||
|
@ -20,15 +21,21 @@ void Remesher::setMesh(const std::vector<QVector3D> &vertices,
|
|||
m_triangles = triangles;
|
||||
}
|
||||
|
||||
const std::vector<QVector3D> &Remesher::getRemeshedVertices()
|
||||
const std::vector<QVector3D> &Remesher::getRemeshedVertices() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<QUuid, QUuid>> &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<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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QObject>
|
||||
#include <vector>
|
||||
#include <QVector3D>
|
||||
#include <QUuid>
|
||||
|
||||
class Remesher : public QObject
|
||||
{
|
||||
|
@ -11,14 +12,21 @@ public:
|
|||
~Remesher();
|
||||
void setMesh(const std::vector<QVector3D> &vertices,
|
||||
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();
|
||||
const std::vector<QVector3D> &getRemeshedVertices();
|
||||
const std::vector<std::vector<size_t>> &getRemeshedFaces();
|
||||
const std::vector<QVector3D> &getRemeshedVertices() const;
|
||||
const std::vector<std::vector<size_t>> &getRemeshedFaces() const;
|
||||
const std::vector<std::pair<QUuid, QUuid>> &getRemeshedVertexSources() const;
|
||||
private:
|
||||
std::vector<QVector3D> m_vertices;
|
||||
std::vector<std::vector<size_t>> m_triangles;
|
||||
std::vector<QVector3D> m_remeshedVertices;
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue