Add base plane constrain settings
Mesh layout and thickness adjustment are depend on base plane calculation. In this build, the base plane calculation could be limited to front plane, side plane, and so on, compare to without any limitation in previous implementation.master
parent
b09df89da2
commit
bb19489ee1
|
@ -298,6 +298,9 @@ HEADERS += src/cutface.h
|
|||
SOURCES += src/parttarget.cpp
|
||||
HEADERS += src/parttarget.h
|
||||
|
||||
SOURCES += src/partbase.cpp
|
||||
HEADERS += src/partbase.h
|
||||
|
||||
SOURCES += src/cutfacewidget.cpp
|
||||
HEADERS += src/cutfacewidget.h
|
||||
|
||||
|
|
|
@ -893,7 +893,10 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
|||
part["subdived"] = partIt.second.subdived ? "true" : "false";
|
||||
part["disabled"] = partIt.second.disabled ? "true" : "false";
|
||||
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
||||
if (partIt.second.zMirrored)
|
||||
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
||||
if (partIt.second.base != PartBase::XYZ)
|
||||
part["base"] = PartBaseToString(partIt.second.base);
|
||||
part["rounded"] = partIt.second.rounded ? "true" : "false";
|
||||
part["chamfered"] = partIt.second.chamfered ? "true" : "false";
|
||||
if (PartTarget::Model != partIt.second.target)
|
||||
|
@ -1163,6 +1166,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
|||
part.disabled = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "disabled"));
|
||||
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
||||
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
||||
part.base = PartBaseFromString(valueOfKeyInMapOrEmpty(partKv.second, "base").toUtf8().constData());
|
||||
part.rounded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "rounded"));
|
||||
part.chamfered = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "chamfered"));
|
||||
part.target = PartTargetFromString(valueOfKeyInMapOrEmpty(partKv.second, "target").toUtf8().constData());
|
||||
|
@ -2219,6 +2223,21 @@ void Document::setPartDeformThickness(QUuid partId, float thickness)
|
|||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void Document::setPartBase(QUuid partId, PartBase base)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
if (part == partMap.end()) {
|
||||
qDebug() << "Part not found:" << partId;
|
||||
return;
|
||||
}
|
||||
if (part->second.base == base)
|
||||
return;
|
||||
part->second.base = base;
|
||||
part->second.dirty = true;
|
||||
emit partBaseChanged(partId);
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void Document::setPartDeformWidth(QUuid partId, float width)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
|
|
|
@ -396,6 +396,7 @@ signals:
|
|||
void partDisableStateChanged(QUuid partId);
|
||||
void partXmirrorStateChanged(QUuid partId);
|
||||
//void partZmirrorStateChanged(QUuid partId);
|
||||
void partBaseChanged(QUuid partId);
|
||||
void partDeformThicknessChanged(QUuid partId);
|
||||
void partDeformWidthChanged(QUuid partId);
|
||||
void partRoundStateChanged(QUuid partId);
|
||||
|
@ -553,6 +554,7 @@ public slots:
|
|||
void setPartDisableState(QUuid partId, bool disabled);
|
||||
void setPartXmirrorState(QUuid partId, bool mirrored);
|
||||
//void setPartZmirrorState(QUuid partId, bool mirrored);
|
||||
void setPartBase(QUuid partId, PartBase base);
|
||||
void setPartDeformThickness(QUuid partId, float thickness);
|
||||
void setPartDeformWidth(QUuid partId, float width);
|
||||
void setPartRoundState(QUuid partId, bool rounded);
|
||||
|
|
|
@ -832,6 +832,7 @@ DocumentWindow::DocumentWindow() :
|
|||
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
||||
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
|
||||
connect(partTreeWidget, &PartTreeWidget::setPartTarget, m_document, &Document::setPartTarget);
|
||||
connect(partTreeWidget, &PartTreeWidget::setPartBase, m_document, &Document::setPartBase);
|
||||
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
||||
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
|
||||
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "cutface.h"
|
||||
#include "parttarget.h"
|
||||
#include "theme.h"
|
||||
#include "partbase.h"
|
||||
|
||||
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
||||
m_snapshot(snapshot)
|
||||
|
@ -171,6 +172,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
|||
float deformWidth = 1.0;
|
||||
float cutRotation = 0.0;
|
||||
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
||||
auto base = PartBaseFromString(valueOfKeyInMapOrEmpty(part, "base").toUtf8().constData());
|
||||
|
||||
std::vector<QVector2D> cutTemplate;
|
||||
QString cutFaceString = valueOfKeyInMapOrEmpty(part, "cutFace");
|
||||
|
@ -441,6 +443,13 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
|||
builder->setDeformThickness(deformThickness);
|
||||
builder->setDeformWidth(deformWidth);
|
||||
builder->setCutRotation(cutRotation);
|
||||
if (PartBase::YZ == base) {
|
||||
builder->enableBaseNormalOnX(false);
|
||||
} else if (PartBase::XY == base) {
|
||||
builder->enableBaseNormalOnZ(false);
|
||||
} else if (PartBase::ZX == base) {
|
||||
builder->enableBaseNormalOnY(false);
|
||||
}
|
||||
|
||||
for (const auto &node: modifier->nodes())
|
||||
builder->addNode(node.position, node.radius, node.cutTemplate);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#include "partbase.h"
|
||||
|
||||
IMPL_PartBaseFromString
|
||||
IMPL_PartBaseToString
|
||||
IMPL_PartBaseToDispName
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef DUST3D_PART_BASE_H
|
||||
#define DUST3D_PART_BASE_H
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
|
||||
enum class PartBase
|
||||
{
|
||||
XYZ = 0,
|
||||
YZ,
|
||||
XY,
|
||||
ZX,
|
||||
Count
|
||||
};
|
||||
PartBase PartBaseFromString(const char *baseString);
|
||||
#define IMPL_PartBaseFromString \
|
||||
PartBase PartBaseFromString(const char *baseString) \
|
||||
{ \
|
||||
QString base = baseString; \
|
||||
if (base == "XYZ") \
|
||||
return PartBase::XYZ; \
|
||||
if (base == "YZ") \
|
||||
return PartBase::YZ; \
|
||||
if (base == "XY") \
|
||||
return PartBase::XY; \
|
||||
if (base == "ZX") \
|
||||
return PartBase::ZX; \
|
||||
return PartBase::XYZ; \
|
||||
}
|
||||
const char *PartBaseToString(PartBase base);
|
||||
#define IMPL_PartBaseToString \
|
||||
const char *PartBaseToString(PartBase base) \
|
||||
{ \
|
||||
switch (base) { \
|
||||
case PartBase::XYZ: \
|
||||
return "XYZ"; \
|
||||
case PartBase::YZ: \
|
||||
return "YZ"; \
|
||||
case PartBase::XY: \
|
||||
return "XY"; \
|
||||
case PartBase::ZX: \
|
||||
return "ZX"; \
|
||||
default: \
|
||||
return "XYZ"; \
|
||||
} \
|
||||
}
|
||||
QString PartBaseToDispName(PartBase base);
|
||||
#define IMPL_PartBaseToDispName \
|
||||
QString PartBaseToDispName(PartBase base) \
|
||||
{ \
|
||||
switch (base) { \
|
||||
case PartBase::XYZ: \
|
||||
return QObject::tr("Dynamic"); \
|
||||
case PartBase::YZ: \
|
||||
return QObject::tr("Side Plane"); \
|
||||
case PartBase::XY: \
|
||||
return QObject::tr("Front Plane"); \
|
||||
case PartBase::ZX: \
|
||||
return QObject::tr("Top Plane"); \
|
||||
default: \
|
||||
return QObject::tr("Dynamic"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
|
@ -294,6 +294,19 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
|||
});
|
||||
}
|
||||
|
||||
QComboBox *partBaseSelectBox = nullptr;
|
||||
if (nullptr != part && nullptr != partWidget) {
|
||||
partBaseSelectBox = new QComboBox;
|
||||
for (size_t i = 0; i < (size_t)PartBase::Count; ++i) {
|
||||
PartBase base = (PartBase)i;
|
||||
partBaseSelectBox->addItem(PartBaseToDispName(base));
|
||||
}
|
||||
partBaseSelectBox->setCurrentIndex((int)part->base);
|
||||
connect(partBaseSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
||||
emit setPartBase(part->id, (PartBase)index);
|
||||
});
|
||||
}
|
||||
|
||||
//QHBoxLayout *combineModeLayout = new QHBoxLayout;
|
||||
//combineModeLayout->setAlignment(Qt::AlignCenter);
|
||||
//combineModeLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -301,6 +314,8 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
|||
//combineModeLayout->addWidget(combineModeSelectBox);
|
||||
|
||||
QFormLayout *componentSettingsLayout = new QFormLayout;
|
||||
if (nullptr != partBaseSelectBox)
|
||||
componentSettingsLayout->addRow(tr("Base"), partBaseSelectBox);
|
||||
if (nullptr != partTargetSelectBox)
|
||||
componentSettingsLayout->addRow(tr("Target"), partTargetSelectBox);
|
||||
componentSettingsLayout->addRow(tr("Mode"), combineModeSelectBox);
|
||||
|
|
|
@ -22,6 +22,7 @@ signals:
|
|||
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
|
||||
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
||||
void setPartTarget(QUuid partId, PartTarget target);
|
||||
void setPartBase(QUuid partId, PartBase base);
|
||||
void moveComponent(QUuid componentId, QUuid toParentId);
|
||||
void removeComponent(QUuid componentId);
|
||||
void hideOtherComponents(QUuid componentId);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "meshloader.h"
|
||||
#include "cutface.h"
|
||||
#include "parttarget.h"
|
||||
#include "partbase.h"
|
||||
|
||||
class SkeletonNode
|
||||
{
|
||||
|
@ -77,6 +78,7 @@ public:
|
|||
bool disabled;
|
||||
bool xMirrored;
|
||||
bool zMirrored;
|
||||
PartBase base;
|
||||
float deformThickness;
|
||||
float deformWidth;
|
||||
bool rounded;
|
||||
|
@ -98,6 +100,7 @@ public:
|
|||
disabled(false),
|
||||
xMirrored(false),
|
||||
zMirrored(false),
|
||||
base(PartBase::XYZ),
|
||||
deformThickness(1.0),
|
||||
deformWidth(1.0),
|
||||
rounded(false),
|
||||
|
@ -189,6 +192,7 @@ public:
|
|||
disabled = other.disabled;
|
||||
xMirrored = other.xMirrored;
|
||||
zMirrored = other.zMirrored;
|
||||
base = other.base;
|
||||
deformThickness = other.deformThickness;
|
||||
deformWidth = other.deformWidth;
|
||||
rounded = other.rounded;
|
||||
|
|
|
@ -289,10 +289,45 @@ bool Builder::validateNormal(const QVector3D &normal)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVector3D> &directs,
|
||||
const std::vector<QVector3D> &positions,
|
||||
void Builder::enableBaseNormalOnX(bool enabled)
|
||||
{
|
||||
m_baseNormalOnX = enabled;
|
||||
}
|
||||
|
||||
void Builder::enableBaseNormalOnY(bool enabled)
|
||||
{
|
||||
m_baseNormalOnY = enabled;
|
||||
}
|
||||
|
||||
void Builder::enableBaseNormalOnZ(bool enabled)
|
||||
{
|
||||
m_baseNormalOnZ = enabled;
|
||||
}
|
||||
|
||||
std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
|
||||
const std::vector<QVector3D> &inputPositions,
|
||||
const std::vector<float> &weights)
|
||||
{
|
||||
std::vector<QVector3D> directs = inputDirects;
|
||||
std::vector<QVector3D> positions = inputPositions;
|
||||
if (!m_baseNormalOnX || !m_baseNormalOnY || !m_baseNormalOnZ) {
|
||||
for (auto &it: directs) {
|
||||
if (!m_baseNormalOnX)
|
||||
it.setX(0);
|
||||
if (!m_baseNormalOnY)
|
||||
it.setY(0);
|
||||
if (!m_baseNormalOnZ)
|
||||
it.setZ(0);
|
||||
}
|
||||
for (auto &it: positions) {
|
||||
if (!m_baseNormalOnX)
|
||||
it.setX(0);
|
||||
if (!m_baseNormalOnY)
|
||||
it.setY(0);
|
||||
if (!m_baseNormalOnZ)
|
||||
it.setZ(0);
|
||||
}
|
||||
}
|
||||
auto calculateTwoPointsNormal = [&](size_t i0, size_t i1) -> std::pair<QVector3D, bool> {
|
||||
auto normal = QVector3D::crossProduct(directs[i0], directs[i1]).normalized();
|
||||
if (validateNormal(normal)) {
|
||||
|
|
|
@ -17,6 +17,9 @@ public:
|
|||
void setDeformThickness(float thickness);
|
||||
void setDeformWidth(float width);
|
||||
void setCutRotation(float cutRotation);
|
||||
void enableBaseNormalOnX(bool enabled);
|
||||
void enableBaseNormalOnY(bool enabled);
|
||||
void enableBaseNormalOnZ(bool enabled);
|
||||
const std::vector<QVector3D> &generatedVertices();
|
||||
const std::vector<std::vector<size_t>> &generatedFaces();
|
||||
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
||||
|
@ -92,11 +95,14 @@ private:
|
|||
float m_deformThickness = 1.0;
|
||||
float m_deformWidth = 1.0;
|
||||
float m_cutRotation = 0.0;
|
||||
bool m_baseNormalOnX = true;
|
||||
bool m_baseNormalOnY = true;
|
||||
bool m_baseNormalOnZ = true;
|
||||
|
||||
void sortNodeIndices();
|
||||
void prepareNode(size_t nodeIndex);
|
||||
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &directs,
|
||||
const std::vector<QVector3D> &positions,
|
||||
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
|
||||
const std::vector<QVector3D> &inputPositions,
|
||||
const std::vector<float> &weights);
|
||||
bool validateNormal(const QVector3D &normal);
|
||||
void resolveBaseNormalRecursively(size_t nodeIndex);
|
||||
|
|
Loading…
Reference in New Issue