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
Jeremy Hu 2019-02-22 08:18:15 +09:30
parent de133b0838
commit d866e0147b
14 changed files with 124 additions and 50 deletions

View File

@ -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) |
+----------------------+--------------------------------------------------------------------------+ +----------------------+--------------------------------------------------------------------------+

View File

@ -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();
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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()

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;

View File

@ -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) {

View File

@ -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:

View File

@ -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;

View File

@ -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);