Fix piece rotation with enabled Follow grainline.

This commit is contained in:
Roman Telezhynskyi 2024-04-12 17:37:13 +03:00
parent e4481754f0
commit 7378cfbe95
9 changed files with 146 additions and 141 deletions

View File

@ -223,40 +223,62 @@ void VPPiece::RotateToGrainline(const VPTransformationOrigon &origin)
} }
QVector<qreal> angles; QVector<qreal> angles;
angles.reserve(4); angles.reserve(8);
const VPieceGrainline pieceGrainline = GetGrainline(); const VPieceGrainline pieceGrainline = GetGrainline();
if (pieceGrainline.IsArrowUpEnabled()) if (pieceGrainline.IsArrowUpEnabled())
{ {
angles.append(grainline.angleTo(fabricGrainline)); qreal const angle = grainline.angleTo(fabricGrainline);
angles.append(angle);
angles.append(-(360. - angle));
} }
if (pieceGrainline.IsArrowDownEnabled()) if (pieceGrainline.IsArrowDownEnabled())
{ {
QLineF arrow = grainline; QLineF arrow = grainline;
arrow.setAngle(arrow.angle() + 180); 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()) if (pieceGrainline.IsArrowLeftEnabled())
{ {
QLineF arrow = grainline; QLineF arrow = grainline;
arrow.setAngle(arrow.angle() + 90); 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()) if (pieceGrainline.IsArrowRightEnabled())
{ {
QLineF arrow = grainline; QLineF arrow = grainline;
arrow.setAngle(arrow.angle() - 90); 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; qreal degrees = 0;
if (not angles.isEmpty()) 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); Rotate(origin.custom ? MappedDetailBoundingRect().center() : origin.origin, degrees);

View File

@ -109,6 +109,11 @@ void VPGraphicsTransformationOrigin::on_HideHandles(bool hide)
void VPGraphicsTransformationOrigin::on_ShowOrigin(bool show) void VPGraphicsTransformationOrigin::on_ShowOrigin(bool show)
{ {
setVisible(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) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
m_rotationStartPoint = event->scenePos(); m_rotationStartPoint = event->scenePos();
m_rotationSum = 0;
m_controlsVisible = false; m_controlsVisible = false;
m_handleCorner = SelectedHandleCorner(event->pos()); m_handleCorner = SelectedHandleCorner(event->pos());
m_ignorePieceTransformation = true; m_ignorePieceTransformation = true;
@ -433,7 +437,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event)
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPGraphicsPieceControls::mouseMoveEvent(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(); QPointF const rotationNewPoint = event->scenePos();
@ -451,24 +455,18 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
if (not qFuzzyIsNull(rotateOn)) if (not qFuzzyIsNull(rotateOn))
{ {
QList<VPPiecePtr> const pieces = SelectedPieces(); if (VPLayoutPtr const layout = m_layout.toStrongRef(); not layout.isNull())
VPLayoutPtr const layout = m_layout.toStrongRef();
if (not layout.isNull())
{ {
CorrectRotationSum(layout, rotationOrigin, rotateOn); QList<VPPiecePtr> const pieces = SelectedPieces();
if (pieces.size() == 1) if (pieces.size() == 1)
{ {
auto *command = new VPUndoPieceRotate(pieces.constFirst(), rotationOrigin, rotateOn, m_rotationSum, layout->UndoStack()->push(
allowChangeMerge); new VPUndoPieceRotate(pieces.constFirst(), rotationOrigin, rotateOn, allowChangeMerge));
layout->UndoStack()->push(command);
} }
else if (pieces.size() > 1) else if (pieces.size() > 1)
{ {
auto *command = layout->UndoStack()->push(new VPUndoPiecesRotate(pieces, rotationOrigin, rotateOn, allowChangeMerge));
new VPUndoPiecesRotate(pieces, rotationOrigin, rotateOn, m_rotationSum, allowChangeMerge);
layout->UndoStack()->push(command);
} }
} }
} }
@ -490,6 +488,19 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) 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<VPPiecePtr> const pieces = SelectedPieces();
for (const auto &piece : qAsConst(pieces))
{
piece->RotateToGrainline(rotationOrigin);
emit layout->PieceTransformationChanged(piece);
}
}
m_controlsVisible = true; m_controlsVisible = true;
m_ignorePieceTransformation = false; m_ignorePieceTransformation = false;
@ -505,9 +516,7 @@ 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())
{ {
@ -521,7 +530,6 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
} }
m_originSaved = false; m_originSaved = false;
} }
}
on_UpdateControls(); on_UpdateControls();
allowChangeMerge = false; allowChangeMerge = false;
@ -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 auto VPGraphicsPieceControls::SelectedHandleCorner(const QPointF &pos) const -> VPHandleCorner
{ {

View File

@ -143,7 +143,6 @@ private:
QRectF m_pieceRect{}; QRectF m_pieceRect{};
QPointF m_rotationStartPoint{}; QPointF m_rotationStartPoint{};
qreal m_rotationSum{0};
bool m_controlsVisible{false}; bool m_controlsVisible{false};
VPLayoutWeakPtr m_layout{}; VPLayoutWeakPtr m_layout{};
VPHandleCorner m_handleCorner{VPHandleCorner::Invalid}; VPHandleCorner m_handleCorner{VPHandleCorner::Invalid};
@ -185,7 +184,6 @@ private:
void UpdateCursor(VPHandleCorner corner); void UpdateCursor(VPHandleCorner corner);
void PrepareTransformationOrigin(bool shiftPressed); void PrepareTransformationOrigin(bool shiftPressed);
void CorrectRotationSum(const VPLayoutPtr &layout, const VPTransformationOrigon &rotationOrigin, qreal rotateOn);
}; };
#endif // VPGRAPHICSPIECECONTROLS_H #endif // VPGRAPHICSPIECECONTROLS_H

View File

@ -320,8 +320,6 @@ void VPMainGraphicsView::keyReleaseEvent(QKeyEvent *event)
sheet->SceneData()->RotationControls()->on_UpdateControls(); sheet->SceneData()->RotationControls()->on_UpdateControls();
sheet->SceneData()->RotationControls()->on_HideHandles(false); sheet->SceneData()->RotationControls()->on_HideHandles(false);
} }
m_rotationSum = 0;
} }
} }
VMainGraphicsView::keyReleaseEvent(event); VMainGraphicsView::keyReleaseEvent(event);
@ -439,31 +437,34 @@ void VPMainGraphicsView::RotatePiecesByAngle(qreal angle)
return pieces; return pieces;
}; };
if (layout->LayoutSettings().GetFollowGrainline() && not origin.custom) QList<VPPiecePtr> const pieces = PreparePieces();
{
if (m_rotationSum > 90 || m_rotationSum < -90)
{
m_rotationSum = angle;
}
else
{
m_rotationSum += angle;
}
}
else
{
m_rotationSum = angle;
}
if (QList<VPPiecePtr> 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(new VPUndoPieceRotate(pieces.constFirst(), origin, angle, m_allowChangeMerge));
layout->UndoStack()->push(command);
} }
else if (pieces.size() > 1) else if (pieces.size() > 1)
{ {
auto *command = new VPUndoPiecesRotate(pieces, origin, angle, m_rotationSum, m_allowChangeMerge); layout->UndoStack()->push(new VPUndoPiecesRotate(pieces, origin, angle, m_allowChangeMerge));
layout->UndoStack()->push(command); }
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; m_allowChangeMerge = true;

View File

@ -29,8 +29,8 @@
#ifndef VPMAINGRAPHICSVIEW_H #ifndef VPMAINGRAPHICSVIEW_H
#define VPMAINGRAPHICSVIEW_H #define VPMAINGRAPHICSVIEW_H
#include "../vwidgets/vmaingraphicsview.h"
#include "../layout/layoutdef.h" #include "../layout/layoutdef.h"
#include "../vwidgets/vmaingraphicsview.h"
class VMainGraphicsScene; class VMainGraphicsScene;
class VPGraphicsPieceControls; class VPGraphicsPieceControls;
@ -45,6 +45,7 @@ class VPPiece;
class VPMainGraphicsView : public VMainGraphicsView class VPMainGraphicsView : public VMainGraphicsView
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
VPMainGraphicsView(const VPLayoutPtr &layout, QWidget *parent); VPMainGraphicsView(const VPLayoutPtr &layout, QWidget *parent);
~VPMainGraphicsView() override = default; ~VPMainGraphicsView() override = default;
@ -98,8 +99,6 @@ private:
bool m_allowChangeMerge{false}; bool m_allowChangeMerge{false};
qreal m_rotationSum{0};
bool m_hasStickyPosition{false}; bool m_hasStickyPosition{false};
qreal m_stickyTranslateX{0}; qreal m_stickyTranslateX{0};
qreal m_stickyTranslateY{0}; qreal m_stickyTranslateY{0};

View File

@ -41,12 +41,11 @@ auto RoundAngle(qreal angle) -> qreal
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle, VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle,
qreal angleSum, bool allowMerge, QUndoCommand *parent) bool allowMerge, QUndoCommand *parent)
: VPUndoCommand(allowMerge, parent), : VPUndoCommand(allowMerge, parent),
m_piece(piece), m_piece(piece),
m_origin(origin), m_origin(origin),
m_angle(angle), m_angle(angle)
m_angleSum(angleSum)
{ {
SCASSERT(not piece.isNull()) SCASSERT(not piece.isNull())
@ -81,6 +80,10 @@ void VPUndoPieceRotate::undo()
} }
piece->SetMatrix(m_oldTransform); piece->SetMatrix(m_oldTransform);
if (m_followGrainline || piece->IsFollowGrainline())
{
piece->RotateToGrainline(m_origin);
}
emit layout->PieceTransformationChanged(piece); emit layout->PieceTransformationChanged(piece);
} }
@ -104,23 +107,9 @@ void VPUndoPieceRotate::redo()
layout->SetFocusedSheet(piece->Sheet()); 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); piece->Rotate(m_origin.origin, m_angle);
}
}
else
{
piece->Rotate(m_origin.origin, m_angle);
}
if (m_followGrainline || piece->IsFollowGrainline()) if (!m_firstCall && (m_followGrainline || piece->IsFollowGrainline()))
{ {
piece->RotateToGrainline(m_origin); piece->RotateToGrainline(m_origin);
} }
@ -168,11 +157,10 @@ auto VPUndoPieceRotate::id() const -> int
// rotate pieces // rotate pieces
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPUndoPiecesRotate::VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin, VPUndoPiecesRotate::VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin,
qreal angle, qreal angleSum, bool allowMerge, QUndoCommand *parent) qreal angle, bool allowMerge, QUndoCommand *parent)
: VPUndoCommand(allowMerge, parent), : VPUndoCommand(allowMerge, parent),
m_origin(origin), m_origin(origin),
m_angle(angle), m_angle(angle)
m_angleSum(angleSum)
{ {
setText(QObject::tr("rotate pieces")); setText(QObject::tr("rotate pieces"));
@ -219,6 +207,10 @@ void VPUndoPiecesRotate::undo()
if (m_oldTransforms.contains(p->GetUniqueID())) if (m_oldTransforms.contains(p->GetUniqueID()))
{ {
p->SetMatrix(m_oldTransforms.value(p->GetUniqueID())); p->SetMatrix(m_oldTransforms.value(p->GetUniqueID()));
if (m_followGrainline || p->IsFollowGrainline())
{
p->RotateToGrainline(m_origin);
}
emit layout->PieceTransformationChanged(p); emit layout->PieceTransformationChanged(p);
} }
} }
@ -248,24 +240,10 @@ void VPUndoPiecesRotate::redo()
{ {
VPPiecePtr const p = piece.toStrongRef(); VPPiecePtr const p = piece.toStrongRef();
if (not p.isNull()) 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); p->Rotate(m_origin.origin, m_angle);
}
}
else
{
p->Rotate(m_origin.origin, m_angle);
}
if (m_followGrainline || p->IsFollowGrainline()) if (!m_firstCall && (m_followGrainline || p->IsFollowGrainline()))
{ {
p->RotateToGrainline(m_origin); p->RotateToGrainline(m_origin);
} }

View File

@ -37,8 +37,9 @@
class VPUndoPieceRotate : public VPUndoCommand class VPUndoPieceRotate : public VPUndoCommand
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: 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); bool allowMerge = false, QUndoCommand *parent = nullptr);
~VPUndoPieceRotate() override = default; ~VPUndoPieceRotate() override = default;
@ -63,7 +64,6 @@ private:
QTransform m_oldTransform{}; QTransform m_oldTransform{};
VPTransformationOrigon m_origin; VPTransformationOrigon m_origin;
qreal m_angle; qreal m_angle;
qreal m_angleSum;
bool m_followGrainline{false}; bool m_followGrainline{false};
}; };
@ -95,9 +95,10 @@ inline auto VPUndoPieceRotate::FollowGrainline() const -> bool
class VPUndoPiecesRotate : public VPUndoCommand class VPUndoPiecesRotate : public VPUndoCommand
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
explicit VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin, qreal angle, explicit VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin, qreal angle,
qreal angleSum, bool allowMerge = false, QUndoCommand *parent = nullptr); bool allowMerge = false, QUndoCommand *parent = nullptr);
~VPUndoPiecesRotate() override = default; ~VPUndoPiecesRotate() override = default;
void undo() override; void undo() override;
@ -119,7 +120,6 @@ private:
QMap<QString, QTransform> m_oldTransforms{}; QMap<QString, QTransform> m_oldTransforms{};
VPTransformationOrigon m_origin; VPTransformationOrigon m_origin;
qreal m_angle; qreal m_angle;
qreal m_angleSum;
bool m_followGrainline{false}; bool m_followGrainline{false};
auto Layout() const -> VPLayoutPtr; auto Layout() const -> VPLayoutPtr;

View File

@ -3521,6 +3521,25 @@ void VPMainWindow::RotatePieces()
return; 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()) if (ui->checkBoxTransformSeparately->isChecked())
{ {
m_layout->UndoStack()->beginMacro(tr("rotate pieces")); m_layout->UndoStack()->beginMacro(tr("rotate pieces"));
@ -3534,7 +3553,9 @@ void VPMainWindow::RotatePieces()
origin.origin = rect.center(); origin.origin = rect.center();
origin.custom = true; 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(); m_layout->UndoStack()->endMacro();
@ -3548,8 +3569,12 @@ void VPMainWindow::RotatePieces()
} }
VPTransformationOrigon const origin = sheet->TransformationOrigin(); VPTransformationOrigon const origin = sheet->TransformationOrigin();
auto *command = new VPUndoPiecesRotate(selectedPieces, origin, angle, angle); m_layout->UndoStack()->push(new VPUndoPiecesRotate(selectedPieces, origin, angle));
m_layout->UndoStack()->push(command);
for (const auto &piece : qAsConst(selectedPieces))
{
StickyRotateToGrainline(piece, origin);
}
} }
} }

View File

@ -2298,11 +2298,11 @@ auto VToolSeamAllowance::FindGrainlineGeometry(const VGrainlineData &geom, const
const auto centerPinPoint = VAbstractTool::data.GeometricObject<VPointF>(centerPin); const auto centerPinPoint = VAbstractTool::data.GeometricObject<VPointF>(centerPin);
const qreal cLength = ToPixel(length, *VDataTool::data.GetPatternUnit()); 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()); centerPinPoint->y());
grainline.setAngle(rotationAngle); grainline.setAngle(rotationAngle);
grainline = QLineF(grainline.p2(), grainline.p1()); Swap(grainline);
grainline.setLength(cLength); grainline.setLength(cLength);
pos = grainline.p2(); pos = grainline.p2();