Fix piece rotation with enabled Follow grainline.

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

View File

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

View File

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

View File

@ -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<VPPiecePtr> const pieces = PreparePieces();
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(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;

View File

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

View File

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

View File

@ -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<VPPiecePtr> &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<VPPieceWeakPtr> m_pieces{};
bool m_firstCall{true};
QVector<VPPieceWeakPtr> m_pieces{};
QMap<QString, QTransform> 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;

View File

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

View File

@ -2298,11 +2298,11 @@ auto VToolSeamAllowance::FindGrainlineGeometry(const VGrainlineData &geom, const
const auto centerPinPoint = VAbstractTool::data.GeometricObject<VPointF>(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();