Add cut rotation tool
Cut rotation tool allow user to adjust the generated face's rotation. Convex hull wrapping tool removed in this commit.master
parent
de133b0838
commit
d866e0147b
|
@ -66,8 +66,6 @@ Keyboard
|
||||||
+----------------------+--------------------------------------------------------------------------+
|
+----------------------+--------------------------------------------------------------------------+
|
||||||
| U | Toggle Part End Roundable |
|
| U | Toggle Part End Roundable |
|
||||||
+----------------------+--------------------------------------------------------------------------+
|
+----------------------+--------------------------------------------------------------------------+
|
||||||
| W | Toggle Part Wrap Status: (W)rap using Convex hull/Normal |
|
|
||||||
+----------------------+--------------------------------------------------------------------------+
|
|
||||||
| E | Swith the Selected Nodes to Different Profile (Main / Side) |
|
| E | Swith the Selected Nodes to Different Profile (Main / Side) |
|
||||||
+----------------------+--------------------------------------------------------------------------+
|
+----------------------+--------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
|
@ -859,7 +859,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
||||||
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
||||||
part["rounded"] = partIt.second.rounded ? "true" : "false";
|
part["rounded"] = partIt.second.rounded ? "true" : "false";
|
||||||
part["wrapped"] = partIt.second.wrapped ? "true" : "false";
|
if (partIt.second.cutRotationAdjusted())
|
||||||
|
part["cutRotation"] = QString::number(partIt.second.cutRotation);
|
||||||
part["dirty"] = partIt.second.dirty ? "true" : "false";
|
part["dirty"] = partIt.second.dirty ? "true" : "false";
|
||||||
if (partIt.second.hasColor)
|
if (partIt.second.hasColor)
|
||||||
part["color"] = partIt.second.color.name();
|
part["color"] = partIt.second.color.name();
|
||||||
|
@ -1114,7 +1115,9 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
||||||
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
||||||
part.rounded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "rounded"));
|
part.rounded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "rounded"));
|
||||||
part.wrapped = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "wrapped"));
|
const auto &cutRotationIt = partKv.second.find("cutRotation");
|
||||||
|
if (cutRotationIt != partKv.second.end())
|
||||||
|
part.setCutRotation(cutRotationIt->second.toFloat());
|
||||||
if (isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "inverse")))
|
if (isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "inverse")))
|
||||||
inversePartIds.insert(part.id);
|
inversePartIds.insert(part.id);
|
||||||
const auto &colorIt = partKv.second.find("color");
|
const auto &colorIt = partKv.second.find("color");
|
||||||
|
@ -2190,18 +2193,16 @@ void Document::setPartRoundState(QUuid partId, bool rounded)
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::setPartWrapState(QUuid partId, bool wrapped)
|
void Document::setPartCutRotation(QUuid partId, float cutRotation)
|
||||||
{
|
{
|
||||||
auto part = partMap.find(partId);
|
auto part = partMap.find(partId);
|
||||||
if (part == partMap.end()) {
|
if (part == partMap.end()) {
|
||||||
qDebug() << "Part not found:" << partId;
|
qDebug() << "Part not found:" << partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (part->second.wrapped == wrapped)
|
part->second.setCutRotation(cutRotation);
|
||||||
return;
|
|
||||||
part->second.wrapped = wrapped;
|
|
||||||
part->second.dirty = true;
|
part->second.dirty = true;
|
||||||
emit partWrapStateChanged(partId);
|
emit partCutRotationChanged(partId);
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -400,7 +400,7 @@ signals:
|
||||||
void partDeformWidthChanged(QUuid partId);
|
void partDeformWidthChanged(QUuid partId);
|
||||||
void partRoundStateChanged(QUuid partId);
|
void partRoundStateChanged(QUuid partId);
|
||||||
void partColorStateChanged(QUuid partId);
|
void partColorStateChanged(QUuid partId);
|
||||||
void partWrapStateChanged(QUuid partId);
|
void partCutRotationChanged(QUuid partId);
|
||||||
void partMaterialIdChanged(QUuid partId);
|
void partMaterialIdChanged(QUuid partId);
|
||||||
void componentCombineModeChanged(QUuid componentId);
|
void componentCombineModeChanged(QUuid componentId);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -553,7 +553,7 @@ public slots:
|
||||||
void setPartDeformWidth(QUuid partId, float width);
|
void setPartDeformWidth(QUuid partId, float width);
|
||||||
void setPartRoundState(QUuid partId, bool rounded);
|
void setPartRoundState(QUuid partId, bool rounded);
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setPartWrapState(QUuid partId, bool wrapped);
|
void setPartCutRotation(QUuid partId, float cutRotation);
|
||||||
void setPartMaterialId(QUuid partId, QUuid materialId);
|
void setPartMaterialId(QUuid partId, QUuid materialId);
|
||||||
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
||||||
void moveComponentUp(QUuid componentId);
|
void moveComponentUp(QUuid componentId);
|
||||||
|
|
|
@ -753,7 +753,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartDisableState, m_document, &Document::setPartDisableState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartDisableState, m_document, &Document::setPartDisableState);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartXmirrorState, m_document, &Document::setPartXmirrorState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartXmirrorState, m_document, &Document::setPartXmirrorState);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartRoundState, m_document, &Document::setPartRoundState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartRoundState, m_document, &Document::setPartRoundState);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartWrapState, m_document, &Document::setPartWrapState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setPartWrapState, m_document, &Document::setPartCutRotation);
|
||||||
|
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setXlockState, m_document, &Document::setXlockState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setXlockState, m_document, &Document::setXlockState);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::setYlockState, m_document, &Document::setYlockState);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::setYlockState, m_document, &Document::setYlockState);
|
||||||
|
@ -831,7 +831,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_document, &Document::partDeformThicknessChanged, partTreeWidget, &PartTreeWidget::partDeformChanged);
|
connect(m_document, &Document::partDeformThicknessChanged, partTreeWidget, &PartTreeWidget::partDeformChanged);
|
||||||
connect(m_document, &Document::partDeformWidthChanged, partTreeWidget, &PartTreeWidget::partDeformChanged);
|
connect(m_document, &Document::partDeformWidthChanged, partTreeWidget, &PartTreeWidget::partDeformChanged);
|
||||||
connect(m_document, &Document::partRoundStateChanged, partTreeWidget, &PartTreeWidget::partRoundStateChanged);
|
connect(m_document, &Document::partRoundStateChanged, partTreeWidget, &PartTreeWidget::partRoundStateChanged);
|
||||||
connect(m_document, &Document::partWrapStateChanged, partTreeWidget, &PartTreeWidget::partWrapStateChanged);
|
connect(m_document, &Document::partCutRotationChanged, partTreeWidget, &PartTreeWidget::partWrapStateChanged);
|
||||||
connect(m_document, &Document::partColorStateChanged, partTreeWidget, &PartTreeWidget::partColorStateChanged);
|
connect(m_document, &Document::partColorStateChanged, partTreeWidget, &PartTreeWidget::partColorStateChanged);
|
||||||
connect(m_document, &Document::partMaterialIdChanged, partTreeWidget, &PartTreeWidget::partMaterialIdChanged);
|
connect(m_document, &Document::partMaterialIdChanged, partTreeWidget, &PartTreeWidget::partMaterialIdChanged);
|
||||||
connect(m_document, &Document::partRemoved, partTreeWidget, &PartTreeWidget::partRemoved);
|
connect(m_document, &Document::partRemoved, partTreeWidget, &PartTreeWidget::partRemoved);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
#include <QMatrix4x4>
|
||||||
#include <nodemesh/builder.h>
|
#include <nodemesh/builder.h>
|
||||||
#include <nodemesh/modifier.h>
|
#include <nodemesh/modifier.h>
|
||||||
#include <nodemesh/misc.h>
|
#include <nodemesh/misc.h>
|
||||||
|
@ -152,6 +153,13 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
||||||
QColor partColor = colorString.isEmpty() ? m_defaultPartColor : QColor(colorString);
|
QColor partColor = colorString.isEmpty() ? m_defaultPartColor : QColor(colorString);
|
||||||
float deformThickness = 1.0;
|
float deformThickness = 1.0;
|
||||||
float deformWidth = 1.0;
|
float deformWidth = 1.0;
|
||||||
|
float cutRotation = 0.0;
|
||||||
|
|
||||||
|
std::vector<QVector2D> cutTemplate = g_defaultCutTemplate;
|
||||||
|
QString cutRotationString = valueOfKeyInMapOrEmpty(part, "cutRotation");
|
||||||
|
if (!cutRotationString.isEmpty()) {
|
||||||
|
cutRotation = cutRotationString.toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
QString thicknessString = valueOfKeyInMapOrEmpty(part, "deformThickness");
|
QString thicknessString = valueOfKeyInMapOrEmpty(part, "deformThickness");
|
||||||
if (!thicknessString.isEmpty()) {
|
if (!thicknessString.isEmpty()) {
|
||||||
|
@ -247,7 +255,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
||||||
for (const auto &nodeIt: nodeInfos) {
|
for (const auto &nodeIt: nodeInfos) {
|
||||||
const auto &nodeIdString = nodeIt.first;
|
const auto &nodeIdString = nodeIt.first;
|
||||||
const auto &nodeInfo = nodeIt.second;
|
const auto &nodeInfo = nodeIt.second;
|
||||||
size_t nodeIndex = modifier->addNode(nodeInfo.position, nodeInfo.radius, g_defaultCutTemplate);
|
size_t nodeIndex = modifier->addNode(nodeInfo.position, nodeInfo.radius, cutTemplate);
|
||||||
nodeIdStringToIndexMap[nodeIdString] = nodeIndex;
|
nodeIdStringToIndexMap[nodeIdString] = nodeIndex;
|
||||||
nodeIndexToIdStringMap[nodeIndex] = nodeIdString;
|
nodeIndexToIdStringMap[nodeIndex] = nodeIdString;
|
||||||
|
|
||||||
|
@ -300,6 +308,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
||||||
nodemesh::Builder *builder = new nodemesh::Builder;
|
nodemesh::Builder *builder = new nodemesh::Builder;
|
||||||
builder->setDeformThickness(deformThickness);
|
builder->setDeformThickness(deformThickness);
|
||||||
builder->setDeformWidth(deformWidth);
|
builder->setDeformWidth(deformWidth);
|
||||||
|
builder->setCutRotation(cutRotation);
|
||||||
|
|
||||||
for (const auto &node: modifier->nodes())
|
for (const auto &node: modifier->nodes())
|
||||||
builder->addNode(node.position, node.radius, node.cutTemplate);
|
builder->addNode(node.position, node.radius, node.cutTemplate);
|
||||||
|
|
|
@ -916,7 +916,7 @@ void PartTreeWidget::partWrapStateChanged(QUuid partId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PartWidget *widget = (PartWidget *)itemWidget(item->second, 0);
|
PartWidget *widget = (PartWidget *)itemWidget(item->second, 0);
|
||||||
widget->updateWrapButton();
|
widget->updateCutRotationButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartTreeWidget::partColorStateChanged(QUuid partId)
|
void PartTreeWidget::partColorStateChanged(QUuid partId)
|
||||||
|
|
|
@ -60,10 +60,10 @@ PartWidget::PartWidget(const Document *document, QUuid partId) :
|
||||||
m_colorButton->setSizePolicy(retainSizePolicy);
|
m_colorButton->setSizePolicy(retainSizePolicy);
|
||||||
initButton(m_colorButton);
|
initButton(m_colorButton);
|
||||||
|
|
||||||
m_wrapButton = new QPushButton;
|
m_cutButton = new QPushButton;
|
||||||
m_wrapButton->setToolTip(tr("Toggle convex wrap"));
|
m_cutButton->setToolTip(tr("Rotation"));
|
||||||
m_wrapButton->setSizePolicy(retainSizePolicy);
|
m_cutButton->setSizePolicy(retainSizePolicy);
|
||||||
initButton(m_wrapButton);
|
initButton(m_cutButton);
|
||||||
|
|
||||||
m_previewWidget = new ModelWidget;
|
m_previewWidget = new ModelWidget;
|
||||||
m_previewWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
|
m_previewWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
@ -90,14 +90,14 @@ PartWidget::PartWidget(const Document *document, QUuid partId) :
|
||||||
int col = 0;
|
int col = 0;
|
||||||
toolsLayout->addWidget(m_lockButton, row, col++, Qt::AlignBottom);
|
toolsLayout->addWidget(m_lockButton, row, col++, Qt::AlignBottom);
|
||||||
toolsLayout->addWidget(m_disableButton, row, col++, Qt::AlignBottom);
|
toolsLayout->addWidget(m_disableButton, row, col++, Qt::AlignBottom);
|
||||||
toolsLayout->addWidget(m_wrapButton, row, col++, Qt::AlignBottom);
|
toolsLayout->addWidget(m_xMirrorButton, row, col++, Qt::AlignBottom);
|
||||||
toolsLayout->addWidget(m_colorButton, row, col++, Qt::AlignBottom);
|
toolsLayout->addWidget(m_colorButton, row, col++, Qt::AlignBottom);
|
||||||
row++;
|
row++;
|
||||||
col = 0;
|
col = 0;
|
||||||
toolsLayout->addWidget(m_subdivButton, row, col++, Qt::AlignTop);
|
toolsLayout->addWidget(m_subdivButton, row, col++, Qt::AlignTop);
|
||||||
toolsLayout->addWidget(m_deformButton, row, col++, Qt::AlignTop);
|
toolsLayout->addWidget(m_cutButton, row, col++, Qt::AlignTop);
|
||||||
toolsLayout->addWidget(m_xMirrorButton, row, col++, Qt::AlignTop);
|
|
||||||
toolsLayout->addWidget(m_roundButton, row, col++, Qt::AlignTop);
|
toolsLayout->addWidget(m_roundButton, row, col++, Qt::AlignTop);
|
||||||
|
toolsLayout->addWidget(m_deformButton, row, col++, Qt::AlignTop);
|
||||||
|
|
||||||
m_visibleButton->setContentsMargins(0, 0, 0, 0);
|
m_visibleButton->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ PartWidget::PartWidget(const Document *document, QUuid partId) :
|
||||||
connect(this, &PartWidget::setPartDeformThickness, m_document, &Document::setPartDeformThickness);
|
connect(this, &PartWidget::setPartDeformThickness, m_document, &Document::setPartDeformThickness);
|
||||||
connect(this, &PartWidget::setPartDeformWidth, m_document, &Document::setPartDeformWidth);
|
connect(this, &PartWidget::setPartDeformWidth, m_document, &Document::setPartDeformWidth);
|
||||||
connect(this, &PartWidget::setPartRoundState, m_document, &Document::setPartRoundState);
|
connect(this, &PartWidget::setPartRoundState, m_document, &Document::setPartRoundState);
|
||||||
connect(this, &PartWidget::setPartWrapState, m_document, &Document::setPartWrapState);
|
connect(this, &PartWidget::setPartCutRotation, m_document, &Document::setPartCutRotation);
|
||||||
connect(this, &PartWidget::setPartColorState, m_document, &Document::setPartColorState);
|
connect(this, &PartWidget::setPartColorState, m_document, &Document::setPartColorState);
|
||||||
connect(this, &PartWidget::setPartMaterialId, m_document, &Document::setPartMaterialId);
|
connect(this, &PartWidget::setPartMaterialId, m_document, &Document::setPartMaterialId);
|
||||||
connect(this, &PartWidget::checkPart, m_document, &Document::checkPart);
|
connect(this, &PartWidget::checkPart, m_document, &Document::checkPart);
|
||||||
|
@ -230,14 +230,13 @@ PartWidget::PartWidget(const Document *document, QUuid partId) :
|
||||||
showColorSettingPopup(mapFromGlobal(QCursor::pos()));
|
showColorSettingPopup(mapFromGlobal(QCursor::pos()));
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_wrapButton, &QPushButton::clicked, [=]() {
|
connect(m_cutButton, &QPushButton::clicked, [=]() {
|
||||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||||
if (!part) {
|
if (!part) {
|
||||||
qDebug() << "Part not found:" << m_partId;
|
qDebug() << "Part not found:" << m_partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit setPartWrapState(m_partId, !part->wrapped);
|
showCutRotationSettingPopup(mapFromGlobal(QCursor::pos()));
|
||||||
emit groupOperationAdded();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
@ -266,7 +265,7 @@ void PartWidget::updateAllButtons()
|
||||||
updateDeformButton();
|
updateDeformButton();
|
||||||
updateRoundButton();
|
updateRoundButton();
|
||||||
updateColorButton();
|
updateColorButton();
|
||||||
updateWrapButton();
|
updateCutRotationButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartWidget::updateCheckedState(bool checked)
|
void PartWidget::updateCheckedState(bool checked)
|
||||||
|
@ -373,6 +372,52 @@ void PartWidget::showColorSettingPopup(const QPoint &pos)
|
||||||
popupMenu.exec(mapToGlobal(pos));
|
popupMenu.exec(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartWidget::showCutRotationSettingPopup(const QPoint &pos)
|
||||||
|
{
|
||||||
|
QMenu popupMenu;
|
||||||
|
|
||||||
|
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||||
|
if (!part) {
|
||||||
|
qDebug() << "Find part failed:" << m_partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *popup = new QWidget;
|
||||||
|
|
||||||
|
FloatNumberWidget *rotationWidget = new FloatNumberWidget;
|
||||||
|
rotationWidget->setItemName(tr("Rotation"));
|
||||||
|
rotationWidget->setRange(-1, 1);
|
||||||
|
rotationWidget->setValue(part->cutRotation);
|
||||||
|
|
||||||
|
connect(rotationWidget, &FloatNumberWidget::valueChanged, [=](float value) {
|
||||||
|
emit setPartCutRotation(m_partId, value);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *rotationEraser = new QPushButton(QChar(fa::eraser));
|
||||||
|
initToolButton(rotationEraser);
|
||||||
|
|
||||||
|
connect(rotationEraser, &QPushButton::clicked, [=]() {
|
||||||
|
rotationWidget->setValue(0.0);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
QHBoxLayout *rotationLayout = new QHBoxLayout;
|
||||||
|
rotationLayout->addWidget(rotationEraser);
|
||||||
|
rotationLayout->addWidget(rotationWidget);
|
||||||
|
layout->addLayout(rotationLayout);
|
||||||
|
|
||||||
|
popup->setLayout(layout);
|
||||||
|
|
||||||
|
QWidgetAction action(this);
|
||||||
|
action.setDefaultWidget(popup);
|
||||||
|
|
||||||
|
popupMenu.addAction(&action);
|
||||||
|
|
||||||
|
popupMenu.exec(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
void PartWidget::showDeformSettingPopup(const QPoint &pos)
|
void PartWidget::showDeformSettingPopup(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QMenu popupMenu;
|
QMenu popupMenu;
|
||||||
|
@ -567,17 +612,17 @@ void PartWidget::updateColorButton()
|
||||||
updateButton(m_colorButton, QChar(fa::eyedropper), false);
|
updateButton(m_colorButton, QChar(fa::eyedropper), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartWidget::updateWrapButton()
|
void PartWidget::updateCutRotationButton()
|
||||||
{
|
{
|
||||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||||
if (!part) {
|
if (!part) {
|
||||||
qDebug() << "Part not found:" << m_partId;
|
qDebug() << "Part not found:" << m_partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (part->wrapped)
|
if (part->cutRotationAdjusted())
|
||||||
updateButton(m_wrapButton, QChar(fa::cube), true);
|
updateButton(m_cutButton, QChar(fa::spinner), true);
|
||||||
else
|
else
|
||||||
updateButton(m_wrapButton, QChar(fa::cube), false);
|
updateButton(m_cutButton, QChar(fa::spinner), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartWidget::reload()
|
void PartWidget::reload()
|
||||||
|
|
|
@ -20,7 +20,7 @@ signals:
|
||||||
void setPartDeformWidth(QUuid partId, float width);
|
void setPartDeformWidth(QUuid partId, float width);
|
||||||
void setPartRoundState(QUuid partId, bool rounded);
|
void setPartRoundState(QUuid partId, bool rounded);
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setPartWrapState(QUuid partId, bool wrapped);
|
void setPartCutRotation(QUuid partId, float cutRotation);
|
||||||
void setPartMaterialId(QUuid partId, QUuid materialId);
|
void setPartMaterialId(QUuid partId, QUuid materialId);
|
||||||
void movePartUp(QUuid partId);
|
void movePartUp(QUuid partId);
|
||||||
void movePartDown(QUuid partId);
|
void movePartDown(QUuid partId);
|
||||||
|
@ -43,7 +43,7 @@ public:
|
||||||
void updateDeformButton();
|
void updateDeformButton();
|
||||||
void updateRoundButton();
|
void updateRoundButton();
|
||||||
void updateColorButton();
|
void updateColorButton();
|
||||||
void updateWrapButton();
|
void updateCutRotationButton();
|
||||||
void updateCheckedState(bool checked);
|
void updateCheckedState(bool checked);
|
||||||
void updateUnnormalState(bool unnormal);
|
void updateUnnormalState(bool unnormal);
|
||||||
static QSize preferredSize();
|
static QSize preferredSize();
|
||||||
|
@ -52,6 +52,7 @@ protected:
|
||||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
public slots:
|
public slots:
|
||||||
void showDeformSettingPopup(const QPoint &pos);
|
void showDeformSettingPopup(const QPoint &pos);
|
||||||
|
void showCutRotationSettingPopup(const QPoint &pos);
|
||||||
void showColorSettingPopup(const QPoint &pos);
|
void showColorSettingPopup(const QPoint &pos);
|
||||||
private: // need initialize
|
private: // need initialize
|
||||||
const Document *m_document;
|
const Document *m_document;
|
||||||
|
@ -68,7 +69,7 @@ private:
|
||||||
QPushButton *m_deformButton;
|
QPushButton *m_deformButton;
|
||||||
QPushButton *m_roundButton;
|
QPushButton *m_roundButton;
|
||||||
QPushButton *m_colorButton;
|
QPushButton *m_colorButton;
|
||||||
QPushButton *m_wrapButton;
|
QPushButton *m_cutButton;
|
||||||
QWidget *m_backgroundWidget;
|
QWidget *m_backgroundWidget;
|
||||||
private:
|
private:
|
||||||
void initToolButton(QPushButton *button);
|
void initToolButton(QPushButton *button);
|
||||||
|
|
|
@ -45,5 +45,4 @@ void initShortCuts(QWidget *widget, SkeletonGraphicsWidget *graphicsWidget)
|
||||||
defineKey(Qt::Key_M, &SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart);
|
defineKey(Qt::Key_M, &SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart);
|
||||||
defineKey(Qt::Key_B, &SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart);
|
defineKey(Qt::Key_B, &SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart);
|
||||||
defineKey(Qt::Key_U, &SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart);
|
defineKey(Qt::Key_U, &SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart);
|
||||||
defineKey(Qt::Key_W, &SkeletonGraphicsWidget::shortcutWrapOrNotSelectedPart);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public:
|
||||||
QUuid componentId;
|
QUuid componentId;
|
||||||
std::vector<QUuid> nodeIds;
|
std::vector<QUuid> nodeIds;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool wrapped;
|
float cutRotation;
|
||||||
QUuid materialId;
|
QUuid materialId;
|
||||||
SkeletonPart(const QUuid &withId=QUuid()) :
|
SkeletonPart(const QUuid &withId=QUuid()) :
|
||||||
visible(true),
|
visible(true),
|
||||||
|
@ -98,7 +98,7 @@ public:
|
||||||
color(Theme::white),
|
color(Theme::white),
|
||||||
hasColor(false),
|
hasColor(false),
|
||||||
dirty(true),
|
dirty(true),
|
||||||
wrapped(false)
|
cutRotation(0.0)
|
||||||
{
|
{
|
||||||
id = withId.isNull() ? QUuid::createUuid() : withId;
|
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,14 @@ public:
|
||||||
toWidth = 2;
|
toWidth = 2;
|
||||||
deformWidth = toWidth;
|
deformWidth = toWidth;
|
||||||
}
|
}
|
||||||
|
void setCutRotation(float toRotation)
|
||||||
|
{
|
||||||
|
if (toRotation < -1)
|
||||||
|
toRotation = -1;
|
||||||
|
else if (toRotation > 1)
|
||||||
|
toRotation = 1;
|
||||||
|
cutRotation = toRotation;
|
||||||
|
}
|
||||||
bool deformThicknessAdjusted() const
|
bool deformThicknessAdjusted() const
|
||||||
{
|
{
|
||||||
return fabs(deformThickness - 1.0) >= 0.01;
|
return fabs(deformThickness - 1.0) >= 0.01;
|
||||||
|
@ -130,6 +138,10 @@ public:
|
||||||
{
|
{
|
||||||
return deformThicknessAdjusted() || deformWidthAdjusted();
|
return deformThicknessAdjusted() || deformWidthAdjusted();
|
||||||
}
|
}
|
||||||
|
bool cutRotationAdjusted() const
|
||||||
|
{
|
||||||
|
return fabs(cutRotation - 0.0) >= 0.01;
|
||||||
|
}
|
||||||
bool materialAdjusted() const
|
bool materialAdjusted() const
|
||||||
{
|
{
|
||||||
return !materialId.isNull();
|
return !materialId.isNull();
|
||||||
|
@ -151,7 +163,7 @@ public:
|
||||||
rounded = other.rounded;
|
rounded = other.rounded;
|
||||||
color = other.color;
|
color = other.color;
|
||||||
hasColor = other.hasColor;
|
hasColor = other.hasColor;
|
||||||
wrapped = other.wrapped;
|
cutRotation = other.cutRotation;
|
||||||
componentId = other.componentId;
|
componentId = other.componentId;
|
||||||
dirty = other.dirty;
|
dirty = other.dirty;
|
||||||
materialId = other.materialId;
|
materialId = other.materialId;
|
||||||
|
|
|
@ -1682,16 +1682,6 @@ void SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::shortcutWrapOrNotSelectedPart()
|
|
||||||
{
|
|
||||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && !m_lastCheckedPart.isNull()) {
|
|
||||||
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
|
|
||||||
bool partWrapped = part && part->wrapped;
|
|
||||||
emit setPartWrapState(m_lastCheckedPart, !partWrapped);
|
|
||||||
emit groupOperationAdded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkeletonGraphicsWidget::keyPress(QKeyEvent *event)
|
bool SkeletonGraphicsWidget::keyPress(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
if (event->key() == Qt::Key_Space) {
|
if (event->key() == Qt::Key_Space) {
|
||||||
|
|
|
@ -507,7 +507,6 @@ public slots:
|
||||||
void shortcutXmirrorOnOrOffSelectedPart();
|
void shortcutXmirrorOnOrOffSelectedPart();
|
||||||
void shortcutSubdivedOrNotSelectedPart();
|
void shortcutSubdivedOrNotSelectedPart();
|
||||||
void shortcutRoundEndOrNotSelectedPart();
|
void shortcutRoundEndOrNotSelectedPart();
|
||||||
void shortcutWrapOrNotSelectedPart();
|
|
||||||
private slots:
|
private slots:
|
||||||
void turnaroundImageReady();
|
void turnaroundImageReady();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <nodemesh/box.h>
|
#include <nodemesh/box.h>
|
||||||
#include <nodemesh/combiner.h>
|
#include <nodemesh/combiner.h>
|
||||||
#include <nodemesh/misc.h>
|
#include <nodemesh/misc.h>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
|
||||||
#define WRAP_STEP_BACK_FACTOR 0.1 // 0.1 ~ 0.9
|
#define WRAP_STEP_BACK_FACTOR 0.1 // 0.1 ~ 0.9
|
||||||
#define WRAP_WELD_FACTOR 0.01 // Allowed distance: WELD_FACTOR * radius
|
#define WRAP_WELD_FACTOR 0.01 // Allowed distance: WELD_FACTOR * radius
|
||||||
|
@ -521,7 +522,19 @@ void Builder::makeCut(const QVector3D &position,
|
||||||
auto uFactor = u * radius;
|
auto uFactor = u * radius;
|
||||||
auto vFactor = v * radius;
|
auto vFactor = v * radius;
|
||||||
for (const auto &t: cutTemplate) {
|
for (const auto &t: cutTemplate) {
|
||||||
resultCut.push_back(position + uFactor * t.x() + vFactor * t.y());
|
resultCut.push_back(uFactor * t.x() + vFactor * t.y());
|
||||||
|
}
|
||||||
|
if (!qFuzzyIsNull(m_cutRotation)) {
|
||||||
|
float degree = m_cutRotation * 180;
|
||||||
|
QMatrix4x4 rotation;
|
||||||
|
rotation.rotate(degree, cutNormal);
|
||||||
|
baseNormal = rotation * baseNormal;
|
||||||
|
for (auto &positionOnCut: resultCut) {
|
||||||
|
positionOnCut = rotation * positionOnCut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &positionOnCut: resultCut) {
|
||||||
|
positionOnCut += position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,6 +611,11 @@ void Builder::setDeformWidth(float width)
|
||||||
m_deformWidth = width;
|
m_deformWidth = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Builder::setCutRotation(float cutRotation)
|
||||||
|
{
|
||||||
|
m_cutRotation = cutRotation;
|
||||||
|
}
|
||||||
|
|
||||||
QVector3D Builder::calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor)
|
QVector3D Builder::calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor)
|
||||||
{
|
{
|
||||||
QVector3D revisedNormal = QVector3D::dotProduct(ray, deformNormal) < 0.0 ? -deformNormal : deformNormal;
|
QVector3D revisedNormal = QVector3D::dotProduct(ray, deformNormal) < 0.0 ? -deformNormal : deformNormal;
|
||||||
|
|
|
@ -16,6 +16,7 @@ public:
|
||||||
size_t addEdge(size_t firstNodeIndex, size_t secondNodeIndex);
|
size_t addEdge(size_t firstNodeIndex, size_t secondNodeIndex);
|
||||||
void setDeformThickness(float thickness);
|
void setDeformThickness(float thickness);
|
||||||
void setDeformWidth(float width);
|
void setDeformWidth(float width);
|
||||||
|
void setCutRotation(float cutRotation);
|
||||||
const std::vector<QVector3D> &generatedVertices();
|
const std::vector<QVector3D> &generatedVertices();
|
||||||
const std::vector<std::vector<size_t>> &generatedFaces();
|
const std::vector<std::vector<size_t>> &generatedFaces();
|
||||||
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
||||||
|
@ -86,6 +87,7 @@ private:
|
||||||
std::set<size_t> m_swallowedNodes;
|
std::set<size_t> m_swallowedNodes;
|
||||||
float m_deformThickness = 1.0;
|
float m_deformThickness = 1.0;
|
||||||
float m_deformWidth = 1.0;
|
float m_deformWidth = 1.0;
|
||||||
|
float m_cutRotation = 0.0;
|
||||||
|
|
||||||
void sortNodeIndices();
|
void sortNodeIndices();
|
||||||
void prepareNode(size_t nodeIndex);
|
void prepareNode(size_t nodeIndex);
|
||||||
|
|
Loading…
Reference in New Issue