From 7378cfbe958cea59eb69a7a051e3bf7435a70c61 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 12 Apr 2024 17:37:13 +0300 Subject: [PATCH] Fix piece rotation with enabled Follow grainline. --- src/app/puzzle/layout/vppiece.cpp | 34 ++++++-- .../puzzle/scene/vpgraphicspiececontrols.cpp | 82 ++++++++----------- .../puzzle/scene/vpgraphicspiececontrols.h | 2 - src/app/puzzle/scene/vpmaingraphicsview.cpp | 45 +++++----- src/app/puzzle/scene/vpmaingraphicsview.h | 5 +- .../puzzle/undocommands/vpundopiecerotate.cpp | 54 ++++-------- .../puzzle/undocommands/vpundopiecerotate.h | 30 +++---- src/app/puzzle/vpmainwindow.cpp | 31 ++++++- src/libs/vtools/tools/vtoolseamallowance.cpp | 4 +- 9 files changed, 146 insertions(+), 141 deletions(-) diff --git a/src/app/puzzle/layout/vppiece.cpp b/src/app/puzzle/layout/vppiece.cpp index 955af0cb2..4024ce5ce 100644 --- a/src/app/puzzle/layout/vppiece.cpp +++ b/src/app/puzzle/layout/vppiece.cpp @@ -223,40 +223,62 @@ void VPPiece::RotateToGrainline(const VPTransformationOrigon &origin) } QVector angles; - angles.reserve(4); + angles.reserve(8); const VPieceGrainline pieceGrainline = GetGrainline(); if (pieceGrainline.IsArrowUpEnabled()) { - angles.append(grainline.angleTo(fabricGrainline)); + qreal const angle = grainline.angleTo(fabricGrainline); + angles.append(angle); + angles.append(-(360. - angle)); } if (pieceGrainline.IsArrowDownEnabled()) { QLineF arrow = grainline; arrow.setAngle(arrow.angle() + 180); - angles.append(arrow.angleTo(fabricGrainline)); + + qreal const angle = arrow.angleTo(fabricGrainline); + angles.append(angle); + angles.append(-(360. - angle)); } if (pieceGrainline.IsArrowLeftEnabled()) { QLineF arrow = grainline; arrow.setAngle(arrow.angle() + 90); - angles.append(arrow.angleTo(fabricGrainline)); + + qreal const angle = arrow.angleTo(fabricGrainline); + angles.append(angle); + angles.append(-(360. - angle)); } if (pieceGrainline.IsArrowRightEnabled()) { QLineF arrow = grainline; arrow.setAngle(arrow.angle() - 90); - angles.append(arrow.angleTo(fabricGrainline)); + + qreal const angle = arrow.angleTo(fabricGrainline); + angles.append(angle); + angles.append(-(360. - angle)); } qreal degrees = 0; if (not angles.isEmpty()) { - degrees = *std::min_element(angles.constBegin(), angles.constEnd()); + qreal minAbsAngle = qAbs(angles.constFirst()); + degrees = angles.constFirst(); + + for (int i = 1; i < angles.size(); ++i) + { + qreal const absAngle = qAbs(angles.at(i)); + if (absAngle < minAbsAngle) + { + minAbsAngle = absAngle; + degrees = angles.at(i); + } + } } Rotate(origin.custom ? MappedDetailBoundingRect().center() : origin.origin, degrees); diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp index 1ee0637b0..1861ad4fa 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp @@ -109,6 +109,11 @@ void VPGraphicsTransformationOrigin::on_HideHandles(bool hide) void VPGraphicsTransformationOrigin::on_ShowOrigin(bool show) { setVisible(show); + + if (not show) + { + m_hoverMode = false; + } } //--------------------------------------------------------------------------------------------------------------------- @@ -404,7 +409,6 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) { m_rotationStartPoint = event->scenePos(); - m_rotationSum = 0; m_controlsVisible = false; m_handleCorner = SelectedHandleCorner(event->pos()); m_ignorePieceTransformation = true; @@ -433,7 +437,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - PrepareTransformationOrigin(event->modifiers() & Qt::ShiftModifier); + PrepareTransformationOrigin(event->modifiers() & Qt::ShiftModifier); // NOLINT(readability-implicit-bool-conversion) QPointF const rotationNewPoint = event->scenePos(); @@ -451,24 +455,18 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (not qFuzzyIsNull(rotateOn)) { - QList const pieces = SelectedPieces(); - - VPLayoutPtr const layout = m_layout.toStrongRef(); - if (not layout.isNull()) + if (VPLayoutPtr const layout = m_layout.toStrongRef(); not layout.isNull()) { - CorrectRotationSum(layout, rotationOrigin, rotateOn); + QList const pieces = SelectedPieces(); if (pieces.size() == 1) { - auto *command = new VPUndoPieceRotate(pieces.constFirst(), rotationOrigin, rotateOn, m_rotationSum, - allowChangeMerge); - layout->UndoStack()->push(command); + layout->UndoStack()->push( + new VPUndoPieceRotate(pieces.constFirst(), rotationOrigin, rotateOn, allowChangeMerge)); } else if (pieces.size() > 1) { - auto *command = - new VPUndoPiecesRotate(pieces, rotationOrigin, rotateOn, m_rotationSum, allowChangeMerge); - layout->UndoStack()->push(command); + layout->UndoStack()->push(new VPUndoPiecesRotate(pieces, rotationOrigin, rotateOn, allowChangeMerge)); } } } @@ -490,6 +488,19 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { + VPLayoutPtr const layout = m_layout.toStrongRef(); + + if (not layout.isNull() && layout->LayoutSettings().GetFollowGrainline()) + { + VPTransformationOrigon const rotationOrigin = TransformationOrigin(m_layout, m_pieceRect); + QList const pieces = SelectedPieces(); + for (const auto &piece : qAsConst(pieces)) + { + piece->RotateToGrainline(rotationOrigin); + emit layout->PieceTransformationChanged(piece); + } + } + m_controlsVisible = true; m_ignorePieceTransformation = false; @@ -505,22 +516,19 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } } - if (m_originSaved) + if (m_originSaved && not layout.isNull()) { - if (VPLayoutPtr const layout = m_layout.toStrongRef(); not layout.isNull()) + if (VPSheetPtr const sheet = layout->GetFocusedSheet(); not sheet.isNull()) { - if (VPSheetPtr const sheet = layout->GetFocusedSheet(); not sheet.isNull()) + if (not m_savedOrigin.custom) { - if (not m_savedOrigin.custom) - { - m_pieceRect = PiecesBoundingRect(m_selectedPieces); - m_savedOrigin.origin = m_pieceRect.center(); - } - sheet->SetTransformationOrigin(m_savedOrigin); - emit TransformationOriginChanged(); + m_pieceRect = PiecesBoundingRect(m_selectedPieces); + m_savedOrigin.origin = m_pieceRect.center(); } - m_originSaved = false; + sheet->SetTransformationOrigin(m_savedOrigin); + emit TransformationOriginChanged(); } + m_originSaved = false; } on_UpdateControls(); @@ -853,32 +861,6 @@ void VPGraphicsPieceControls::PrepareTransformationOrigin(bool shiftPressed) } } -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPieceControls::CorrectRotationSum(const VPLayoutPtr &layout, - const VPTransformationOrigon &rotationOrigin, qreal rotateOn) -{ - if (layout.isNull()) - { - return; - } - - if (layout->LayoutSettings().GetFollowGrainline() && not rotationOrigin.custom) - { - if (m_rotationSum > 90 || m_rotationSum < -90) - { - m_rotationSum = rotateOn; - } - else - { - m_rotationSum += rotateOn; - } - } - else - { - m_rotationSum = rotateOn; - } -} - //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPieceControls::SelectedHandleCorner(const QPointF &pos) const -> VPHandleCorner { diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.h b/src/app/puzzle/scene/vpgraphicspiececontrols.h index 02ef14fe8..71440a7bf 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.h +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.h @@ -143,7 +143,6 @@ private: QRectF m_pieceRect{}; QPointF m_rotationStartPoint{}; - qreal m_rotationSum{0}; bool m_controlsVisible{false}; VPLayoutWeakPtr m_layout{}; VPHandleCorner m_handleCorner{VPHandleCorner::Invalid}; @@ -185,7 +184,6 @@ private: void UpdateCursor(VPHandleCorner corner); void PrepareTransformationOrigin(bool shiftPressed); - void CorrectRotationSum(const VPLayoutPtr &layout, const VPTransformationOrigon &rotationOrigin, qreal rotateOn); }; #endif // VPGRAPHICSPIECECONTROLS_H diff --git a/src/app/puzzle/scene/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp index 74b7731a8..80209bcd5 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -320,8 +320,6 @@ void VPMainGraphicsView::keyReleaseEvent(QKeyEvent *event) sheet->SceneData()->RotationControls()->on_UpdateControls(); sheet->SceneData()->RotationControls()->on_HideHandles(false); } - - m_rotationSum = 0; } } VMainGraphicsView::keyReleaseEvent(event); @@ -439,31 +437,34 @@ void VPMainGraphicsView::RotatePiecesByAngle(qreal angle) return pieces; }; - if (layout->LayoutSettings().GetFollowGrainline() && not origin.custom) - { - if (m_rotationSum > 90 || m_rotationSum < -90) - { - m_rotationSum = angle; - } - else - { - m_rotationSum += angle; - } - } - else - { - m_rotationSum = angle; - } + QList const pieces = PreparePieces(); - if (QList const pieces = PreparePieces(); pieces.size() == 1) + if (pieces.size() == 1) { - auto *command = new VPUndoPieceRotate(pieces.constFirst(), origin, angle, m_rotationSum, m_allowChangeMerge); - layout->UndoStack()->push(command); + layout->UndoStack()->push(new VPUndoPieceRotate(pieces.constFirst(), origin, angle, m_allowChangeMerge)); } else if (pieces.size() > 1) { - auto *command = new VPUndoPiecesRotate(pieces, origin, angle, m_rotationSum, m_allowChangeMerge); - layout->UndoStack()->push(command); + layout->UndoStack()->push(new VPUndoPiecesRotate(pieces, origin, angle, m_allowChangeMerge)); + } + + QTime const dieTime = QTime::currentTime().addMSecs(150); + while (QTime::currentTime() < dieTime) + { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + } + + for (const auto &piece : qAsConst(pieces)) + { + if (not piece.isNull()) + { + if (layout->LayoutSettings().GetFollowGrainline() || piece->IsFollowGrainline()) + { + piece->RotateToGrainline(origin); + } + + emit layout->PieceTransformationChanged(piece); + } } m_allowChangeMerge = true; diff --git a/src/app/puzzle/scene/vpmaingraphicsview.h b/src/app/puzzle/scene/vpmaingraphicsview.h index 0452304bc..ac854c206 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.h +++ b/src/app/puzzle/scene/vpmaingraphicsview.h @@ -29,8 +29,8 @@ #ifndef VPMAINGRAPHICSVIEW_H #define VPMAINGRAPHICSVIEW_H -#include "../vwidgets/vmaingraphicsview.h" #include "../layout/layoutdef.h" +#include "../vwidgets/vmaingraphicsview.h" class VMainGraphicsScene; class VPGraphicsPieceControls; @@ -45,6 +45,7 @@ class VPPiece; class VPMainGraphicsView : public VMainGraphicsView { Q_OBJECT // NOLINT + public: VPMainGraphicsView(const VPLayoutPtr &layout, QWidget *parent); ~VPMainGraphicsView() override = default; @@ -98,8 +99,6 @@ private: bool m_allowChangeMerge{false}; - qreal m_rotationSum{0}; - bool m_hasStickyPosition{false}; qreal m_stickyTranslateX{0}; qreal m_stickyTranslateY{0}; diff --git a/src/app/puzzle/undocommands/vpundopiecerotate.cpp b/src/app/puzzle/undocommands/vpundopiecerotate.cpp index cf33704e1..215e78fd8 100644 --- a/src/app/puzzle/undocommands/vpundopiecerotate.cpp +++ b/src/app/puzzle/undocommands/vpundopiecerotate.cpp @@ -41,12 +41,11 @@ auto RoundAngle(qreal angle) -> qreal //--------------------------------------------------------------------------------------------------------------------- VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle, - qreal angleSum, bool allowMerge, QUndoCommand *parent) + bool allowMerge, QUndoCommand *parent) : VPUndoCommand(allowMerge, parent), m_piece(piece), m_origin(origin), - m_angle(angle), - m_angleSum(angleSum) + m_angle(angle) { SCASSERT(not piece.isNull()) @@ -81,6 +80,10 @@ void VPUndoPieceRotate::undo() } piece->SetMatrix(m_oldTransform); + if (m_followGrainline || piece->IsFollowGrainline()) + { + piece->RotateToGrainline(m_origin); + } emit layout->PieceTransformationChanged(piece); } @@ -104,23 +107,9 @@ void VPUndoPieceRotate::redo() layout->SetFocusedSheet(piece->Sheet()); } - if (m_firstCall) - { - if ((m_followGrainline || piece->IsFollowGrainline()) && piece->IsGrainlineEnabled()) - { - piece->Rotate(m_origin.origin, m_angleSum); - } - else - { - piece->Rotate(m_origin.origin, m_angle); - } - } - else - { - piece->Rotate(m_origin.origin, m_angle); - } + piece->Rotate(m_origin.origin, m_angle); - if (m_followGrainline || piece->IsFollowGrainline()) + if (!m_firstCall && (m_followGrainline || piece->IsFollowGrainline())) { piece->RotateToGrainline(m_origin); } @@ -168,11 +157,10 @@ auto VPUndoPieceRotate::id() const -> int // rotate pieces //--------------------------------------------------------------------------------------------------------------------- VPUndoPiecesRotate::VPUndoPiecesRotate(const QList &pieces, const VPTransformationOrigon &origin, - qreal angle, qreal angleSum, bool allowMerge, QUndoCommand *parent) + qreal angle, bool allowMerge, QUndoCommand *parent) : VPUndoCommand(allowMerge, parent), m_origin(origin), - m_angle(angle), - m_angleSum(angleSum) + m_angle(angle) { setText(QObject::tr("rotate pieces")); @@ -219,6 +207,10 @@ void VPUndoPiecesRotate::undo() if (m_oldTransforms.contains(p->GetUniqueID())) { p->SetMatrix(m_oldTransforms.value(p->GetUniqueID())); + if (m_followGrainline || p->IsFollowGrainline()) + { + p->RotateToGrainline(m_origin); + } emit layout->PieceTransformationChanged(p); } } @@ -249,23 +241,9 @@ void VPUndoPiecesRotate::redo() VPPiecePtr const p = piece.toStrongRef(); if (not p.isNull()) { - if (m_firstCall) - { - if ((m_followGrainline || p->IsFollowGrainline()) && p->IsGrainlineEnabled()) - { - p->Rotate(m_origin.origin, m_angleSum); - } - else - { - p->Rotate(m_origin.origin, m_angle); - } - } - else - { - p->Rotate(m_origin.origin, m_angle); - } + p->Rotate(m_origin.origin, m_angle); - if (m_followGrainline || p->IsFollowGrainline()) + if (!m_firstCall && (m_followGrainline || p->IsFollowGrainline())) { p->RotateToGrainline(m_origin); } diff --git a/src/app/puzzle/undocommands/vpundopiecerotate.h b/src/app/puzzle/undocommands/vpundopiecerotate.h index c21639fe1..84d63402e 100644 --- a/src/app/puzzle/undocommands/vpundopiecerotate.h +++ b/src/app/puzzle/undocommands/vpundopiecerotate.h @@ -37,11 +37,12 @@ class VPUndoPieceRotate : public VPUndoCommand { Q_OBJECT // NOLINT + public: - VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle, qreal angleSum, + VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle, bool allowMerge = false, QUndoCommand *parent = nullptr); - ~VPUndoPieceRotate() override =default; + ~VPUndoPieceRotate() override = default; void undo() override; void redo() override; @@ -58,13 +59,12 @@ public: private: Q_DISABLE_COPY_MOVE(VPUndoPieceRotate) // NOLINT - bool m_firstCall{true}; + bool m_firstCall{true}; VPPieceWeakPtr m_piece; - QTransform m_oldTransform{}; + QTransform m_oldTransform{}; VPTransformationOrigon m_origin; - qreal m_angle; - qreal m_angleSum; - bool m_followGrainline{false}; + qreal m_angle; + bool m_followGrainline{false}; }; //--------------------------------------------------------------------------------------------------------------------- @@ -95,10 +95,11 @@ inline auto VPUndoPieceRotate::FollowGrainline() const -> bool class VPUndoPiecesRotate : public VPUndoCommand { Q_OBJECT // NOLINT + public: explicit VPUndoPiecesRotate(const QList &pieces, const VPTransformationOrigon &origin, qreal angle, - qreal angleSum, bool allowMerge = false, QUndoCommand *parent = nullptr); - ~VPUndoPiecesRotate() override =default; + bool allowMerge = false, QUndoCommand *parent = nullptr); + ~VPUndoPiecesRotate() override = default; void undo() override; void redo() override; @@ -114,13 +115,12 @@ public: private: Q_DISABLE_COPY_MOVE(VPUndoPiecesRotate) // NOLINT - bool m_firstCall{true}; - QVector m_pieces{}; + bool m_firstCall{true}; + QVector m_pieces{}; QMap m_oldTransforms{}; - VPTransformationOrigon m_origin; - qreal m_angle; - qreal m_angleSum; - bool m_followGrainline{false}; + VPTransformationOrigon m_origin; + qreal m_angle; + bool m_followGrainline{false}; auto Layout() const -> VPLayoutPtr; auto Sheet() const -> VPSheetPtr; diff --git a/src/app/puzzle/vpmainwindow.cpp b/src/app/puzzle/vpmainwindow.cpp index d0f8a253a..03afe4d91 100644 --- a/src/app/puzzle/vpmainwindow.cpp +++ b/src/app/puzzle/vpmainwindow.cpp @@ -3521,6 +3521,25 @@ void VPMainWindow::RotatePieces() return; } + auto StickyRotateToGrainline = [this](const VPPiecePtr &piece, const VPTransformationOrigon &origin) + { + QTime const dieTime = QTime::currentTime().addMSecs(150); + while (QTime::currentTime() < dieTime) + { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + } + + if (not piece.isNull()) + { + if (m_layout->LayoutSettings().GetFollowGrainline() || piece->IsFollowGrainline()) + { + piece->RotateToGrainline(origin); + } + + emit m_layout->PieceTransformationChanged(piece); + } + }; + if (ui->checkBoxTransformSeparately->isChecked()) { m_layout->UndoStack()->beginMacro(tr("rotate pieces")); @@ -3534,7 +3553,9 @@ void VPMainWindow::RotatePieces() origin.origin = rect.center(); origin.custom = true; - m_layout->UndoStack()->push(new VPUndoPieceRotate(piece, origin, angle, angle)); + m_layout->UndoStack()->push(new VPUndoPieceRotate(piece, origin, angle)); + + StickyRotateToGrainline(piece, origin); } } m_layout->UndoStack()->endMacro(); @@ -3548,8 +3569,12 @@ void VPMainWindow::RotatePieces() } VPTransformationOrigon const origin = sheet->TransformationOrigin(); - auto *command = new VPUndoPiecesRotate(selectedPieces, origin, angle, angle); - m_layout->UndoStack()->push(command); + m_layout->UndoStack()->push(new VPUndoPiecesRotate(selectedPieces, origin, angle)); + + for (const auto &piece : qAsConst(selectedPieces)) + { + StickyRotateToGrainline(piece, origin); + } } } diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index 6f188beaf..7428880a4 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -2298,11 +2298,11 @@ auto VToolSeamAllowance::FindGrainlineGeometry(const VGrainlineData &geom, const const auto centerPinPoint = VAbstractTool::data.GeometricObject(centerPin); const qreal cLength = ToPixel(length, *VDataTool::data.GetPatternUnit()); - QLineF grainline(centerPinPoint->x(), centerPinPoint->y(), centerPinPoint->x() + cLength / 2.0, + QLineF grainline(centerPinPoint->x(), centerPinPoint->y(), centerPinPoint->x() - cLength / 2.0, centerPinPoint->y()); grainline.setAngle(rotationAngle); - grainline = QLineF(grainline.p2(), grainline.p1()); + Swap(grainline); grainline.setLength(cLength); pos = grainline.p2();