Add base normal rotation

master
Jeremy HU 2022-10-14 22:11:41 +11:00
parent a9dd15991f
commit 73b3dc3941
9 changed files with 151 additions and 6 deletions

View File

@ -4,6 +4,7 @@
#include <QPushButton> #include <QPushButton>
#include <QColorDialog> #include <QColorDialog>
#include "component_property_widget.h" #include "component_property_widget.h"
#include "float_number_widget.h"
#include "document.h" #include "document.h"
#include "theme.h" #include "theme.h"
@ -22,21 +23,140 @@ ComponentPropertyWidget::ComponentPropertyWidget(Document *document,
colorPreviewArea->setFixedSize(Theme::toolIconSize * 1.8, Theme::toolIconSize); colorPreviewArea->setFixedSize(Theme::toolIconSize * 1.8, Theme::toolIconSize);
QPushButton *colorPickerButton = new QPushButton(QChar(fa::eyedropper)); QPushButton *colorPickerButton = new QPushButton(QChar(fa::eyedropper));
colorPickerButton->setFixedSize(Theme::toolIconSize, Theme::toolIconSize); Theme::initIconButton(colorPickerButton);
connect(colorPickerButton, &QPushButton::clicked, this, &ComponentPropertyWidget::showColorDialog); connect(colorPickerButton, &QPushButton::clicked, this, &ComponentPropertyWidget::showColorDialog);
QHBoxLayout *colorLayout = new QHBoxLayout; QHBoxLayout *colorLayout = new QHBoxLayout;
colorLayout->addWidget(colorPreviewArea); colorLayout->addWidget(colorPreviewArea);
colorLayout->addWidget(colorPickerButton); colorLayout->addWidget(colorPickerButton);
colorLayout->addStretch();
colorLayout->setSizeConstraint(QLayout::SetFixedSize); colorLayout->setSizeConstraint(QLayout::SetFixedSize);
QVBoxLayout *deformLayout = nullptr;
if (nullptr != m_part) {
FloatNumberWidget *thicknessWidget = new FloatNumberWidget;
thicknessWidget->setItemName(tr("Thickness"));
thicknessWidget->setRange(0, 2);
thicknessWidget->setValue(m_part->deformThickness);
connect(thicknessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
emit setPartDeformThickness(m_partId, value);
emit groupOperationAdded();
});
FloatNumberWidget *widthWidget = new FloatNumberWidget;
widthWidget->setItemName(tr("Width"));
widthWidget->setRange(0, 2);
widthWidget->setValue(m_part->deformWidth);
connect(widthWidget, &FloatNumberWidget::valueChanged, [=](float value) {
emit setPartDeformWidth(m_partId, value);
emit groupOperationAdded();
});
QPushButton *thicknessEraser = new QPushButton(QChar(fa::eraser));
Theme::initIconButton(thicknessEraser);
connect(thicknessEraser, &QPushButton::clicked, [=]() {
thicknessWidget->setValue(1.0);
emit groupOperationAdded();
});
QPushButton *widthEraser = new QPushButton(QChar(fa::eraser));
Theme::initIconButton(widthEraser);
connect(widthEraser, &QPushButton::clicked, [=]() {
widthWidget->setValue(1.0);
emit groupOperationAdded();
});
deformLayout = new QVBoxLayout;
QHBoxLayout *thicknessLayout = new QHBoxLayout;
QHBoxLayout *widthLayout = new QHBoxLayout;
thicknessLayout->addWidget(thicknessEraser);
thicknessLayout->addWidget(thicknessWidget);
widthLayout->addWidget(widthEraser);
widthLayout->addWidget(widthWidget);
QCheckBox *deformUnifyStateBox = new QCheckBox();
Theme::initCheckbox(deformUnifyStateBox);
deformUnifyStateBox->setText(tr("Unified"));
deformUnifyStateBox->setChecked(m_part->deformUnified);
connect(deformUnifyStateBox, &QCheckBox::stateChanged, this, [=]() {
emit setPartDeformUnified(m_partId, deformUnifyStateBox->isChecked());
emit groupOperationAdded();
});
QHBoxLayout *deformUnifyLayout = new QHBoxLayout;
deformUnifyLayout->addStretch();
deformUnifyLayout->addWidget(deformUnifyStateBox);
deformLayout->addLayout(thicknessLayout);
deformLayout->addLayout(widthLayout);
deformLayout->addLayout(deformUnifyLayout);
}
QHBoxLayout *rotationLayout = nullptr;
if (nullptr != m_part) {
FloatNumberWidget *rotationWidget = new FloatNumberWidget;
rotationWidget->setItemName(tr("Rotation"));
rotationWidget->setRange(-1, 1);
rotationWidget->setValue(m_part->cutRotation);
connect(rotationWidget, &FloatNumberWidget::valueChanged, [=](float value) {
emit setPartCutRotation(m_partId, value);
emit groupOperationAdded();
});
QPushButton *rotationEraser = new QPushButton(QChar(fa::eraser));
Theme::initIconButton(rotationEraser);
connect(rotationEraser, &QPushButton::clicked, [=]() {
rotationWidget->setValue(0.0);
emit groupOperationAdded();
});
QPushButton *rotationMinus5Button = new QPushButton(QChar(fa::rotateleft));
Theme::initIconButton(rotationMinus5Button);
connect(rotationMinus5Button, &QPushButton::clicked, [=]() {
rotationWidget->setValue(-0.5);
emit groupOperationAdded();
});
QPushButton *rotation5Button = new QPushButton(QChar(fa::rotateright));
Theme::initIconButton(rotation5Button);
connect(rotation5Button, &QPushButton::clicked, [=]() {
rotationWidget->setValue(0.5);
emit groupOperationAdded();
});
rotationLayout = new QHBoxLayout;
rotationLayout->addWidget(rotationEraser);
rotationLayout->addWidget(rotationWidget);
rotationLayout->addWidget(rotationMinus5Button);
rotationLayout->addWidget(rotation5Button);
}
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(colorLayout); mainLayout->addLayout(colorLayout);
if (nullptr != deformLayout)
mainLayout->addLayout(deformLayout);
if (nullptr != rotationLayout)
mainLayout->addLayout(rotationLayout);
mainLayout->setSizeConstraint(QLayout::SetFixedSize); mainLayout->setSizeConstraint(QLayout::SetFixedSize);
connect(this, &ComponentPropertyWidget::setPartColorState, m_document, &Document::setPartColorState); connect(this, &ComponentPropertyWidget::setPartColorState, m_document, &Document::setPartColorState);
connect(this, &ComponentPropertyWidget::endColorPicking, m_document, &Document::enableBackgroundBlur); connect(this, &ComponentPropertyWidget::endColorPicking, m_document, &Document::enableBackgroundBlur);
connect(this, &ComponentPropertyWidget::beginColorPicking, m_document, &Document::disableBackgroundBlur); connect(this, &ComponentPropertyWidget::beginColorPicking, m_document, &Document::disableBackgroundBlur);
connect(this, &ComponentPropertyWidget::setPartDeformThickness, m_document, &Document::setPartDeformThickness);
connect(this, &ComponentPropertyWidget::setPartDeformWidth, m_document, &Document::setPartDeformWidth);
connect(this, &ComponentPropertyWidget::setPartDeformUnified, m_document, &Document::setPartDeformUnified);
connect(this, &ComponentPropertyWidget::setPartCutRotation, m_document, &Document::setPartCutRotation);
connect(this, &ComponentPropertyWidget::groupOperationAdded, m_document, &Document::saveSnapshot); connect(this, &ComponentPropertyWidget::groupOperationAdded, m_document, &Document::saveSnapshot);
setLayout(mainLayout); setLayout(mainLayout);
@ -55,6 +175,11 @@ void ComponentPropertyWidget::preparePartIds()
m_partIds.emplace_back(it); m_partIds.emplace_back(it);
} }
} }
if (1 == m_partIds.size()) {
m_part = m_document->findPart(m_partIds.front());
if (nullptr != m_part)
m_partId = m_partIds.front();
}
} }
QColor ComponentPropertyWidget::lastColor() QColor ComponentPropertyWidget::lastColor()

View File

@ -5,6 +5,7 @@
#include <QWidget> #include <QWidget>
class Document; class Document;
class SkeletonPart;
class ComponentPropertyWidget: public QWidget class ComponentPropertyWidget: public QWidget
{ {
@ -13,6 +14,10 @@ signals:
void beginColorPicking(); void beginColorPicking();
void endColorPicking(); void endColorPicking();
void setPartColorState(const dust3d::Uuid &partId, bool hasColor, const QColor &color); void setPartColorState(const dust3d::Uuid &partId, bool hasColor, const QColor &color);
void setPartDeformThickness(const dust3d::Uuid &partId, float thickness);
void setPartDeformWidth(const dust3d::Uuid &partId, float width);
void setPartDeformUnified(const dust3d::Uuid &partId, bool unified);
void setPartCutRotation(const dust3d::Uuid &partId, float cutRotation);
void groupOperationAdded(); void groupOperationAdded();
public: public:
ComponentPropertyWidget(Document *document, ComponentPropertyWidget(Document *document,
@ -24,6 +29,8 @@ private:
Document *m_document = nullptr; Document *m_document = nullptr;
std::vector<dust3d::Uuid> m_componentIds; std::vector<dust3d::Uuid> m_componentIds;
std::vector<dust3d::Uuid> m_partIds; std::vector<dust3d::Uuid> m_partIds;
dust3d::Uuid m_partId;
const SkeletonPart *m_part = nullptr;
QColor m_color; QColor m_color;
QColor lastColor(); QColor lastColor();
void preparePartIds(); void preparePartIds();

View File

@ -29,7 +29,7 @@ QImage *buildCutFaceTemplatePreviewImage(const std::vector<dust3d::Vector2> &cut
const float scale = 0.7f; const float scale = 0.7f;
QPolygon polygon; QPolygon polygon;
for (int i = 0; i <= cutTemplate.size(); ++i) { for (size_t i = 0; i <= cutTemplate.size(); ++i) {
const auto &it = cutTemplate[i % cutTemplate.size()]; const auto &it = cutTemplate[i % cutTemplate.size()];
polygon.append(QPoint((it.x() * scale + 1.0) * 0.5 * Theme::partPreviewImageSize, polygon.append(QPoint((it.x() * scale + 1.0) * 0.5 * Theme::partPreviewImageSize,
(it.y() * scale + 1.0) * 0.5 * Theme::partPreviewImageSize)); (it.y() * scale + 1.0) * 0.5 * Theme::partPreviewImageSize));

View File

@ -22,7 +22,7 @@ PartManageWidget::PartManageWidget(Document *document, QWidget *parent):
auto createButton = [](QChar icon, const QString &title) { auto createButton = [](QChar icon, const QString &title) {
QPushButton *button = new QPushButton(icon); QPushButton *button = new QPushButton(icon);
button->setFixedSize(Theme::toolIconSize, Theme::toolIconSize); Theme::initIconButton(button);
button->setToolTip(title); button->setToolTip(title);
return button; return button;
}; };

View File

@ -158,3 +158,8 @@ void Theme::initCheckbox(QCheckBox *checkbox)
palette.setColor(QPalette::Background, Theme::white); palette.setColor(QPalette::Background, Theme::white);
checkbox->setPalette(palette); checkbox->setPalette(palette);
} }
void Theme::initIconButton(QPushButton *button)
{
button->setFixedSize(Theme::toolIconSize, Theme::toolIconSize);
}

View File

@ -43,6 +43,7 @@ public:
static void initAwsome(); static void initAwsome();
static void initToolButton(QPushButton *button); static void initToolButton(QPushButton *button);
static void initCheckbox(QCheckBox *checkbox); static void initCheckbox(QCheckBox *checkbox);
static void initIconButton(QPushButton *button);
}; };
#endif #endif

View File

@ -659,6 +659,10 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::st
return nullptr; return nullptr;
TubeMeshBuilder::BuildParameters buildParameters; TubeMeshBuilder::BuildParameters buildParameters;
buildParameters.deformThickness = deformThickness;
buildParameters.deformWidth = deformWidth;
buildParameters.deformUnified = deformUnified;
buildParameters.baseNormalRotation = cutRotation * Math::Pi;
buildParameters.cutFace = cutTemplate; buildParameters.cutFace = cutTemplate;
auto tubeMeshBuilder = std::make_unique<TubeMeshBuilder>(buildParameters, std::move(meshNodes), isCircle); auto tubeMeshBuilder = std::make_unique<TubeMeshBuilder>(buildParameters, std::move(meshNodes), isCircle);
tubeMeshBuilder->build(); tubeMeshBuilder->build();

View File

@ -94,8 +94,8 @@ std::vector<Vector3> TubeMeshBuilder::buildCutFaceVertices(const Vector3 &origin
const Vector3 &forwardDirection) const Vector3 &forwardDirection)
{ {
std::vector<Vector3> cutFaceVertices(m_buildParameters.cutFace.size()); std::vector<Vector3> cutFaceVertices(m_buildParameters.cutFace.size());
Vector3 u = m_generatedBaseNormal; Vector3 u = m_generatedBaseNormal.rotated(-forwardDirection, m_buildParameters.baseNormalRotation);
Vector3 v = Vector3::crossProduct(forwardDirection, m_generatedBaseNormal).normalized(); Vector3 v = Vector3::crossProduct(forwardDirection, u).normalized();
auto uFactor = u * radius; auto uFactor = u * radius;
auto vFactor = v * radius; auto vFactor = v * radius;
for (size_t i = 0; i < m_buildParameters.cutFace.size(); ++i) { for (size_t i = 0; i < m_buildParameters.cutFace.size(); ++i) {

View File

@ -37,7 +37,10 @@ public:
struct BuildParameters struct BuildParameters
{ {
std::vector<Vector2> cutFace; std::vector<Vector2> cutFace;
double baseNormalRotation; double deformThickness = 1.0;
double deformWidth = 1.0;
bool deformUnified = false;
double baseNormalRotation = 0.0;
}; };
TubeMeshBuilder(const BuildParameters &buildParameters, std::vector<MeshNode> &&nodes, bool isCircle); TubeMeshBuilder(const BuildParameters &buildParameters, std::vector<MeshNode> &&nodes, bool isCircle);