Follow grainline.

This commit is contained in:
Roman Telezhynskyi 2021-08-26 19:04:24 +03:00
parent acfbc5478e
commit 877fe380e3
22 changed files with 310 additions and 57 deletions

View File

@ -55,6 +55,21 @@ struct VPTransformationOrigon
{ {
QPointF origin{}; QPointF origin{};
bool custom{false}; bool custom{false};
bool operator==(const VPTransformationOrigon &origin) const;
bool operator!=(const VPTransformationOrigon &origin) const;
}; };
//---------------------------------------------------------------------------------------------------------------------
inline bool VPTransformationOrigon::operator==(const VPTransformationOrigon &origin) const
{
return this->origin == origin.origin && custom == origin.custom;
}
//---------------------------------------------------------------------------------------------------------------------
inline bool VPTransformationOrigon::operator!=(const VPTransformationOrigon &origin) const
{
return !VPTransformationOrigon::operator==(origin);
}
#endif // LAYOUTDEF_H #endif // LAYOUTDEF_H

View File

@ -108,6 +108,23 @@ auto VPLayout::GetPieces() const -> QList<VPPiecePtr>
return m_pieces.values(); return m_pieces.values();
} }
//---------------------------------------------------------------------------------------------------------------------
auto VPLayout::GetPlacedPieces() const -> QList<VPPiecePtr>
{
QList<VPPiecePtr> pieces;
pieces.reserve(m_pieces.size());
for (const auto& piece : m_pieces)
{
if (not piece->isNull() && piece->Sheet() != VPSheetPtr() && piece->Sheet() != m_trashSheet)
{
pieces.append(piece);
}
}
return pieces;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPLayout::GetUnplacedPieces() const -> QList<VPPiecePtr> auto VPLayout::GetUnplacedPieces() const -> QList<VPPiecePtr>
{ {

View File

@ -49,6 +49,7 @@ public:
static void AddPiece(const VPLayoutPtr &layout, const VPPiecePtr &piece); static void AddPiece(const VPLayoutPtr &layout, const VPPiecePtr &piece);
auto GetPieces() const -> QList<VPPiecePtr>; auto GetPieces() const -> QList<VPPiecePtr>;
auto GetPlacedPieces() const -> QList<VPPiecePtr>;
auto GetUnplacedPieces() const -> QList<VPPiecePtr>; auto GetUnplacedPieces() const -> QList<VPPiecePtr>;
auto GetTrashedPieces() const -> QList<VPPiecePtr>; auto GetTrashedPieces() const -> QList<VPPiecePtr>;

View File

@ -76,7 +76,7 @@ auto VPPiece::GetPosition() -> QPointF
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPPiece::RotateToGrainline() void VPPiece::RotateToGrainline(const VPTransformationOrigon &origin)
{ {
VPSheetPtr sheet = Sheet(); VPSheetPtr sheet = Sheet();
if (not IsGrainlineEnabled() || sheet.isNull()) if (not IsGrainlineEnabled() || sheet.isNull())
@ -105,7 +105,8 @@ void VPPiece::RotateToGrainline()
atFront.setAngle(90); atFront.setAngle(90);
} }
return grainline.angleTo(atFront); qreal angleTo = grainline.angleTo(atFront);
return angleTo;
}; };
auto DegreesAtRear = [grainline, canonical, grainlineType]() auto DegreesAtRear = [grainline, canonical, grainlineType]()
@ -113,7 +114,8 @@ void VPPiece::RotateToGrainline()
QLineF atRear = canonical; QLineF atRear = canonical;
atRear.setAngle(grainlineType == GrainlineType::Vertical ? 270 : 180); atRear.setAngle(grainlineType == GrainlineType::Vertical ? 270 : 180);
return grainline.angleTo(atRear); qreal angleTo = grainline.angleTo(atRear);
return angleTo;
}; };
GrainlineArrowDirection type = GrainlineArrowType(); GrainlineArrowDirection type = GrainlineArrowType();
@ -129,10 +131,25 @@ void VPPiece::RotateToGrainline()
} }
else else
{ {
degrees = qMin(DegreesAtFront(), DegreesAtRear()); const qreal atFront = DegreesAtFront();
if (atFront <= 90 || atFront >= 270)
{
degrees = atFront;
}
else
{
degrees = DegreesAtRear();
}
} }
if (origin.custom)
{
Rotate(MappedDetailBoundingRect().center(), degrees); Rotate(MappedDetailBoundingRect().center(), degrees);
}
else
{
Rotate(origin.origin, degrees);
}
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -64,7 +64,7 @@ public:
/** /**
* @brief RotateToGrainline rotates the piece to follow the grainline * @brief RotateToGrainline rotates the piece to follow the grainline
*/ */
void RotateToGrainline(); void RotateToGrainline(const VPTransformationOrigon &origin);
/** /**
* @brief SetSelected Sets wether the piece is selected * @brief SetSelected Sets wether the piece is selected

View File

@ -71,17 +71,20 @@ enum class HandleCorner : int
BottomLeft = 4 BottomLeft = 4
}; };
auto TransformationOrigin(const VPLayoutPtr &layout, const QRectF &boundingRect) -> QPointF auto TransformationOrigin(const VPLayoutPtr &layout, const QRectF &boundingRect) -> VPTransformationOrigon
{ {
SCASSERT(layout != nullptr) SCASSERT(layout != nullptr)
VPSheetPtr sheet = layout->GetFocusedSheet(); VPSheetPtr sheet = layout->GetFocusedSheet();
if (not sheet.isNull()) if (not sheet.isNull())
{ {
VPTransformationOrigon origin = sheet->TransformationOrigin(); return sheet->TransformationOrigin();
return origin.origin;
} }
return boundingRect.center(); VPTransformationOrigon origin;
origin.origin = boundingRect.center();
origin.custom = false;
return origin;
} }
} // namespace } // namespace
@ -233,8 +236,8 @@ auto VPGraphicsTransformationOrigin::RotationCenter(QPainter *painter) const ->
const qreal scale = SceneScale(scene()); const qreal scale = SceneScale(scene());
qreal radius = centerRadius1/scale; qreal radius = centerRadius1/scale;
QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); VPTransformationOrigon transformationOrigin = TransformationOrigin(m_layout, QRectF());
QRectF rect(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); QRectF rect(transformationOrigin.origin.x()-radius, transformationOrigin.origin.y()-radius, radius*2., radius*2.);
QPainterPath center1; QPainterPath center1;
center1.addEllipse(rect); center1.addEllipse(rect);
@ -249,7 +252,7 @@ auto VPGraphicsTransformationOrigin::RotationCenter(QPainter *painter) const ->
path.addPath(center1); path.addPath(center1);
radius = centerRadius2/scale; radius = centerRadius2/scale;
rect = QRectF(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); rect = QRectF(transformationOrigin.origin.x()-radius, transformationOrigin.origin.y()-radius, radius*2., radius*2.);
QPainterPath center2; QPainterPath center2;
center2.addEllipse(rect); center2.addEllipse(rect);
@ -271,8 +274,8 @@ auto VPGraphicsTransformationOrigin::Center1() const -> QPainterPath
{ {
const qreal scale = SceneScale(scene()); const qreal scale = SceneScale(scene());
qreal radius = centerRadius1/scale; qreal radius = centerRadius1/scale;
QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); VPTransformationOrigon transformationOrigin = TransformationOrigin(m_layout, QRectF());
QRectF rect(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); QRectF rect(transformationOrigin.origin.x()-radius, transformationOrigin.origin.y()-radius, radius*2., radius*2.);
QPainterPath center1; QPainterPath center1;
center1.addEllipse(rect); center1.addEllipse(rect);
@ -285,8 +288,9 @@ auto VPGraphicsTransformationOrigin::Center2() const -> QPainterPath
{ {
const qreal scale = SceneScale(scene()); const qreal scale = SceneScale(scene());
qreal radius = centerRadius2/scale; qreal radius = centerRadius2/scale;
QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); VPTransformationOrigon transformationOrigin = TransformationOrigin(m_layout, QRectF());
QRectF rect = QRectF(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); QRectF rect = QRectF(transformationOrigin.origin.x()-radius, transformationOrigin.origin.y()-radius, radius*2.,
radius*2.);
QPainterPath center2; QPainterPath center2;
center2.addEllipse(rect); center2.addEllipse(rect);
@ -389,6 +393,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event)
if(event->button() == Qt::LeftButton) if(event->button() == Qt::LeftButton)
{ {
m_rotationStartPoint = event->scenePos(); m_rotationStartPoint = event->scenePos();
m_rotationSum = 0;
m_controlsVisible = false; m_controlsVisible = false;
m_handleCorner = HandleCorner(event->scenePos()); m_handleCorner = HandleCorner(event->scenePos());
m_ignorePieceTransformation = true; m_ignorePieceTransformation = true;
@ -470,13 +475,18 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
QPointF rotationNewPoint = event->scenePos(); QPointF rotationNewPoint = event->scenePos();
// get the angle from the center to the initial click point // get the angle from the center to the initial click point
QPointF rotationOrigin = TransformationOrigin(m_layout, m_pieceRect); VPTransformationOrigon rotationOrigin = TransformationOrigin(m_layout, m_pieceRect);
QLineF initPosition(rotationOrigin, m_rotationStartPoint); QLineF initPosition(rotationOrigin.origin, m_rotationStartPoint);
QLineF initRotationPosition(rotationOrigin, rotationNewPoint); QLineF initRotationPosition(rotationOrigin.origin, rotationNewPoint);
qreal angle = initPosition.angleTo(initRotationPosition); qreal rotateOn = initPosition.angleTo(initRotationPosition);
if (not qFuzzyIsNull(angle)) if (rotateOn > 180)
{
rotateOn = rotateOn - 360.;
}
if (not qFuzzyIsNull(rotateOn))
{ {
auto PreparePieces = [this]() auto PreparePieces = [this]()
{ {
@ -499,14 +509,32 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
VPLayoutPtr layout = m_layout.toStrongRef(); VPLayoutPtr layout = m_layout.toStrongRef();
if (not layout.isNull()) if (not layout.isNull())
{ {
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;
}
if (pieces.size() == 1) if (pieces.size() == 1)
{ {
auto *command = new VPUndoPieceRotate(pieces.first(), rotationOrigin, angle, allowChangeMerge); auto *command = new VPUndoPieceRotate(pieces.first(), rotationOrigin, rotateOn, m_rotationSum,
allowChangeMerge);
layout->UndoStack()->push(command); layout->UndoStack()->push(command);
} }
else if (pieces.size() > 1) else if (pieces.size() > 1)
{ {
auto *command = new VPUndoPiecesRotate(pieces, rotationOrigin, angle, allowChangeMerge); auto *command = new VPUndoPiecesRotate(pieces, rotationOrigin, rotateOn, m_rotationSum,
allowChangeMerge);
layout->UndoStack()->push(command); layout->UndoStack()->push(command);
} }
} }
@ -514,8 +542,8 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
if (m_originSaved && m_savedOrigin.custom) if (m_originSaved && m_savedOrigin.custom)
{ {
QLineF line(rotationOrigin, m_savedOrigin.origin); QLineF line(rotationOrigin.origin, m_savedOrigin.origin);
line.setAngle(line.angle()+angle); line.setAngle(line.angle()+rotateOn);
m_savedOrigin.origin = line.p2(); m_savedOrigin.origin = line.p2();
} }

View File

@ -108,6 +108,7 @@ private:
Q_DISABLE_COPY(VPGraphicsPieceControls) Q_DISABLE_COPY(VPGraphicsPieceControls)
QRectF m_pieceRect{}; QRectF m_pieceRect{};
QPointF m_rotationStartPoint{}; QPointF m_rotationStartPoint{};
qreal m_rotationSum{0};
bool m_controlsVisible{true}; bool m_controlsVisible{true};
VPLayoutWeakPtr m_layout{}; VPLayoutWeakPtr m_layout{};
int m_handleCorner{0}; int m_handleCorner{0};

View File

@ -371,6 +371,7 @@ void VPMainGraphicsView::keyReleaseEvent(QKeyEvent *event)
m_rotationControls->SetIgnorePieceTransformation(false); m_rotationControls->SetIgnorePieceTransformation(false);
m_rotationControls->on_UpdateControls(); m_rotationControls->on_UpdateControls();
m_rotationControls->on_HideHandles(false); m_rotationControls->on_HideHandles(false);
m_rotationSum = 0;
} }
} }
VMainGraphicsView::keyReleaseEvent(event); VMainGraphicsView::keyReleaseEvent(event);
@ -558,16 +559,32 @@ void VPMainGraphicsView::RotatePiecesByAngle(qreal angle)
return pieces; 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> pieces = PreparePieces(); QList<VPPiecePtr> pieces = PreparePieces();
if (pieces.size() == 1) if (pieces.size() == 1)
{ {
auto *command = new VPUndoPieceRotate(pieces.first(), origin.origin, angle, m_allowChangeMerge); auto *command = new VPUndoPieceRotate(pieces.first(), origin, angle, m_rotationSum, m_allowChangeMerge);
layout->UndoStack()->push(command); layout->UndoStack()->push(command);
} }
else if (pieces.size() > 1) else if (pieces.size() > 1)
{ {
auto *command = new VPUndoPiecesRotate(pieces, origin.origin, angle, m_allowChangeMerge); auto *command = new VPUndoPiecesRotate(pieces, origin, angle, m_rotationSum, m_allowChangeMerge);
layout->UndoStack()->push(command); layout->UndoStack()->push(command);
} }

View File

@ -124,6 +124,8 @@ private:
bool m_showGridTmp{false}; bool m_showGridTmp{false};
bool m_allowChangeMerge{false}; bool m_allowChangeMerge{false};
qreal m_rotationSum{0};
void ConnectPiece(VPGraphicsPiece *piece); void ConnectPiece(VPGraphicsPiece *piece);
void RotatePiecesByAngle(qreal angle); void RotatePiecesByAngle(qreal angle);

View File

@ -41,6 +41,12 @@ VPUndoMovePieceOnSheet::VPUndoMovePieceOnSheet(const VPSheetPtr &sheet, const VP
m_oldSheet = piece->Sheet(); m_oldSheet = piece->Sheet();
VPLayoutPtr layout = piece->Layout();
if (not layout.isNull())
{
m_followGrainline = layout->LayoutSettings().GetFollowGrainline();
}
setText(tr("move piece on sheet")); setText(tr("move piece on sheet"));
} }
@ -105,6 +111,14 @@ void VPUndoMovePieceOnSheet::redo()
{ {
piece->SetSheet(sourceSheet); piece->SetSheet(sourceSheet);
if (m_followGrainline)
{
VPTransformationOrigon origin;
origin.custom = true;
piece->RotateToGrainline(origin);
}
if (not layout.isNull()) if (not layout.isNull())
{ {
emit layout->PieceSheetChanged(piece); emit layout->PieceSheetChanged(piece);

View File

@ -48,6 +48,7 @@ private:
VPSheetWeakPtr m_oldSheet{}; VPSheetWeakPtr m_oldSheet{};
VPSheetWeakPtr m_sheet; VPSheetWeakPtr m_sheet;
VPPieceWeakPtr m_piece; VPPieceWeakPtr m_piece;
bool m_followGrainline{false};
}; };
#endif // VPUNDOMOVEPIECEONSHEET_H #endif // VPUNDOMOVEPIECEONSHEET_H

View File

@ -29,18 +29,35 @@
#include "../layout/vppiece.h" #include "../layout/vppiece.h"
#include "../layout/vplayout.h" #include "../layout/vplayout.h"
namespace
{
auto RoundAngle(qreal angle) -> qreal
{
QLineF l(10, 10, 100, 10);
l.setAngle(angle);
return l.angle();
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const QPointF &origin, qreal angle, bool allowMerge, VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle,
QUndoCommand *parent) qreal angleSum, 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())
m_oldTransform = piece->GetMatrix(); m_oldTransform = piece->GetMatrix();
VPLayoutPtr layout = piece->Layout();
if (not layout.isNull())
{
m_followGrainline = layout->LayoutSettings().GetFollowGrainline();
}
setText(tr("rotate piece")); setText(tr("rotate piece"));
} }
@ -88,8 +105,33 @@ void VPUndoPieceRotate::redo()
layout->SetFocusedSheet(piece->Sheet()); layout->SetFocusedSheet(piece->Sheet());
} }
piece->Rotate(m_origin, m_angle); if (m_firstCall)
{
if (m_followGrainline && 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);
}
if (m_followGrainline)
{
piece->RotateToGrainline(m_origin);
}
emit layout->PieceTransformationChanged(piece); emit layout->PieceTransformationChanged(piece);
if (m_firstCall)
{
m_firstCall = false;
}
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -105,12 +147,14 @@ auto VPUndoPieceRotate::mergeWith(const QUndoCommand *command) -> bool
VPPiecePtr piece = Piece(); VPPiecePtr piece = Piece();
if (not moveCommand->AllowMerge() || (moveCommand->Piece().isNull() || piece.isNull()) || if (not moveCommand->AllowMerge() || (moveCommand->Piece().isNull() || piece.isNull()) ||
moveCommand->Piece() != piece || moveCommand->Origin() != m_origin) moveCommand->Piece() != piece || moveCommand->Origin() != m_origin ||
moveCommand->FollowGrainline() != m_followGrainline)
{ {
return false; return false;
} }
m_angle += moveCommand->Angle(); m_angle += moveCommand->Angle();
m_angle = RoundAngle(m_angle);
return true; return true;
} }
@ -122,11 +166,12 @@ auto VPUndoPieceRotate::id() const -> int
// rotate pieces // rotate pieces
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPUndoPiecesRotate::VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const QPointF &origin, qreal angle, VPUndoPiecesRotate::VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin,
bool allowMerge, QUndoCommand *parent) qreal angle, qreal angleSum, 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"));
@ -138,6 +183,12 @@ VPUndoPiecesRotate::VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const QP
m_oldTransforms.insert(piece->GetUniqueID(), piece->GetMatrix()); m_oldTransforms.insert(piece->GetUniqueID(), piece->GetMatrix());
} }
} }
VPLayoutPtr layout = Layout();
if (not layout.isNull())
{
m_followGrainline = layout->LayoutSettings().GetFollowGrainline();
}
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -199,10 +250,35 @@ void VPUndoPiecesRotate::redo()
VPPiecePtr p = piece.toStrongRef(); VPPiecePtr p = piece.toStrongRef();
if (not p.isNull()) if (not p.isNull())
{ {
p->Rotate(m_origin, m_angle); if (m_firstCall)
{
if (m_followGrainline && 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);
}
if (m_followGrainline)
{
p->RotateToGrainline(m_origin);
}
emit layout->PieceTransformationChanged(p); emit layout->PieceTransformationChanged(p);
} }
} }
if (m_firstCall)
{
m_firstCall = false;
}
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -216,12 +292,14 @@ auto VPUndoPiecesRotate::mergeWith(const QUndoCommand *command) -> bool
const auto *moveCommand = dynamic_cast<const VPUndoPiecesRotate *>(command); const auto *moveCommand = dynamic_cast<const VPUndoPiecesRotate *>(command);
SCASSERT(moveCommand != nullptr) SCASSERT(moveCommand != nullptr)
if (not moveCommand->AllowMerge() || moveCommand->PieceIds() != PieceIds() || moveCommand->Origin() != m_origin) if (not moveCommand->AllowMerge() || moveCommand->PieceIds() != PieceIds() || moveCommand->Origin() != m_origin ||
moveCommand->FollowGrainline() != m_followGrainline)
{ {
return false; return false;
} }
m_angle += moveCommand->Angle(); m_angle += moveCommand->Angle();
m_angle = RoundAngle(m_angle);
return true; return true;
} }

View File

@ -38,8 +38,8 @@ class VPUndoPieceRotate : public VPUndoCommand
{ {
Q_OBJECT Q_OBJECT
public: public:
VPUndoPieceRotate(const VPPiecePtr &piece, const QPointF &origin, qreal angle, bool allowMerge = false, VPUndoPieceRotate(const VPPiecePtr &piece, const VPTransformationOrigon &origin, qreal angle, qreal angleSum,
QUndoCommand *parent = nullptr); bool allowMerge = false, QUndoCommand *parent = nullptr);
virtual ~VPUndoPieceRotate()=default; virtual ~VPUndoPieceRotate()=default;
@ -50,16 +50,21 @@ public:
virtual auto id() const -> int override ; virtual auto id() const -> int override ;
auto Piece() const -> VPPiecePtr; auto Piece() const -> VPPiecePtr;
auto Origin() const -> QPointF; auto Origin() const -> VPTransformationOrigon;
auto Angle() const -> qreal; auto Angle() const -> qreal;
bool FollowGrainline() const;
private: private:
Q_DISABLE_COPY(VPUndoPieceRotate) Q_DISABLE_COPY(VPUndoPieceRotate)
bool m_firstCall{true};
VPPieceWeakPtr m_piece; VPPieceWeakPtr m_piece;
QTransform m_oldTransform{}; QTransform m_oldTransform{};
QPointF m_origin; VPTransformationOrigon m_origin;
qreal m_angle; qreal m_angle;
qreal m_angleSum;
bool m_followGrainline{false};
}; };
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -69,7 +74,7 @@ inline auto VPUndoPieceRotate::Piece() const -> VPPiecePtr
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
inline auto VPUndoPieceRotate::Origin() const -> QPointF inline auto VPUndoPieceRotate::Origin() const -> VPTransformationOrigon
{ {
return m_origin; return m_origin;
} }
@ -80,13 +85,19 @@ inline auto VPUndoPieceRotate::Angle() const -> qreal
return m_angle; return m_angle;
} }
//---------------------------------------------------------------------------------------------------------------------
inline auto VPUndoPieceRotate::FollowGrainline() const -> bool
{
return m_followGrainline;
}
// Rotate pieces // Rotate pieces
class VPUndoPiecesRotate : public VPUndoCommand class VPUndoPiecesRotate : public VPUndoCommand
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const QPointF &origin, qreal angle, explicit VPUndoPiecesRotate(const QList<VPPiecePtr> &pieces, const VPTransformationOrigon &origin, qreal angle,
bool allowMerge = false, QUndoCommand *parent = nullptr); qreal angleSum, bool allowMerge = false, QUndoCommand *parent = nullptr);
virtual ~VPUndoPiecesRotate()=default; virtual ~VPUndoPiecesRotate()=default;
virtual void undo() override; virtual void undo() override;
@ -96,23 +107,27 @@ public:
virtual auto id() const -> int override ; virtual auto id() const -> int override ;
auto PieceIds() const -> QSet<QString>; auto PieceIds() const -> QSet<QString>;
auto Origin() const -> QPointF; auto Origin() const -> VPTransformationOrigon;
auto Angle() const -> qreal; auto Angle() const -> qreal;
auto FollowGrainline() const -> bool;
private: private:
Q_DISABLE_COPY(VPUndoPiecesRotate) Q_DISABLE_COPY(VPUndoPiecesRotate)
bool m_firstCall{true};
QVector<VPPieceWeakPtr> m_pieces{}; QVector<VPPieceWeakPtr> m_pieces{};
QMap<QString, QTransform> m_oldTransforms{}; QMap<QString, QTransform> m_oldTransforms{};
QPointF m_origin; VPTransformationOrigon m_origin;
qreal m_angle; qreal m_angle;
qreal m_angleSum;
bool m_followGrainline{false};
auto Layout() const -> VPLayoutPtr; auto Layout() const -> VPLayoutPtr;
auto Sheet() const -> VPSheetPtr; auto Sheet() const -> VPSheetPtr;
}; };
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
inline auto VPUndoPiecesRotate::Origin() const -> QPointF inline auto VPUndoPiecesRotate::Origin() const -> VPTransformationOrigon
{ {
return m_origin; return m_origin;
} }
@ -123,4 +138,10 @@ inline auto VPUndoPiecesRotate::Angle() const -> qreal
return m_angle; return m_angle;
} }
//---------------------------------------------------------------------------------------------------------------------
inline auto VPUndoPiecesRotate::FollowGrainline() const -> bool
{
return m_followGrainline;
}
#endif // VPUNDOPIECEROTATE_H #endif // VPUNDOPIECEROTATE_H

View File

@ -862,8 +862,13 @@ void VPMainWindow::InitPropertyTabLayout()
if (not m_layout.isNull()) if (not m_layout.isNull())
{ {
m_layout->LayoutSettings().SetFollowGrainline(checked); m_layout->LayoutSettings().SetFollowGrainline(checked);
if (checked)
{
RotatePiecesToGrainline();
}
LayoutWasSaved(false); LayoutWasSaved(false);
// TODO update the QGraphicView
} }
}); });
@ -1742,6 +1747,11 @@ void VPMainWindow::SheetPaperSizeChanged()
ui->toolButtonSheetLandscapeOrientation->blockSignals(true); ui->toolButtonSheetLandscapeOrientation->blockSignals(true);
ui->toolButtonSheetLandscapeOrientation->setChecked(not portrait); ui->toolButtonSheetLandscapeOrientation->setChecked(not portrait);
ui->toolButtonSheetLandscapeOrientation->blockSignals(false); ui->toolButtonSheetLandscapeOrientation->blockSignals(false);
if (not m_layout.isNull() && m_layout->LayoutSettings().GetFollowGrainline())
{
RotatePiecesToGrainline();
}
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -1862,6 +1872,29 @@ void VPMainWindow::CorrectMaxMargins()
CorrectTileMaxMargins(); CorrectTileMaxMargins();
} }
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::RotatePiecesToGrainline()
{
QList<VPSheetPtr> sheets = m_layout->GetSheets();
for(const auto& sheet : sheets)
{
if (not sheet.isNull())
{
QList<VPPiecePtr> pieces = sheet->GetPieces();
for(const auto& piece : pieces)
{
if (not piece.isNull() && piece->IsGrainlineEnabled())
{
VPTransformationOrigon origin;
origin.custom = true;
piece->RotateToGrainline(origin);
emit m_layout->PieceTransformationChanged(piece);
}
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionNew_triggered() void VPMainWindow::on_actionNew_triggered()
{ {
@ -2513,7 +2546,12 @@ void VPMainWindow::on_ApplyPieceTransformation()
if (not piece.isNull()) if (not piece.isNull())
{ {
const QRectF rect = piece->MappedDetailBoundingRect(); const QRectF rect = piece->MappedDetailBoundingRect();
auto *command = new VPUndoPieceRotate(piece, rect.center(), angle);
VPTransformationOrigon origin;
origin.origin = rect.center();
origin.custom = true;
auto *command = new VPUndoPieceRotate(piece, origin, angle, angle);
m_layout->UndoStack()->push(command); m_layout->UndoStack()->push(command);
} }
} }
@ -2528,7 +2566,7 @@ void VPMainWindow::on_ApplyPieceTransformation()
} }
VPTransformationOrigon origin = sheet->TransformationOrigin(); VPTransformationOrigon origin = sheet->TransformationOrigin();
auto *command = new VPUndoPiecesRotate(selectedPieces, origin.origin, angle); auto *command = new VPUndoPiecesRotate(selectedPieces, origin, angle, angle);
m_layout->UndoStack()->push(command); m_layout->UndoStack()->push(command);
} }
} }

View File

@ -454,6 +454,8 @@ private:
void CorrectTileMaxMargins(); void CorrectTileMaxMargins();
void CorrectSheetMaxMargins(); void CorrectSheetMaxMargins();
void CorrectMaxMargins(); void CorrectMaxMargins();
void RotatePiecesToGrainline();
}; };
#endif // VPMAINWINDOW_H #endif // VPMAINWINDOW_H

View File

@ -189,7 +189,7 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>3</number>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>

View File

@ -298,7 +298,7 @@ void VPLayoutFileReader::ReadControl(const VPLayoutPtr &layout)
layout->LayoutSettings().SetWarningPiecesOutOfBound(ReadAttributeBool(attribs, ML::AttrWarningOutOfBound, trueStr)); layout->LayoutSettings().SetWarningPiecesOutOfBound(ReadAttributeBool(attribs, ML::AttrWarningOutOfBound, trueStr));
layout->LayoutSettings().SetStickyEdges(ReadAttributeBool(attribs, ML::AttrStickyEdges, trueStr)); layout->LayoutSettings().SetStickyEdges(ReadAttributeBool(attribs, ML::AttrStickyEdges, trueStr));
layout->LayoutSettings().SetPiecesGap(ReadAttributeDouble(attribs, ML::AttrPiecesGap, QChar('0'))); layout->LayoutSettings().SetPiecesGap(ReadAttributeDouble(attribs, ML::AttrPiecesGap, QChar('0')));
// layout->LayoutSettings().SetFollowGrainline(ReadAttributeBool(attribs, ML::AttrFollowGrainLine, trueStr)); layout->LayoutSettings().SetFollowGrainline(ReadAttributeBool(attribs, ML::AttrFollowGrainline, falseStr));
readElementText(); readElementText();
} }

View File

@ -176,7 +176,7 @@ void VPLayoutFileWriter::WriteProperties(const VPLayoutPtr &layout)
SetAttribute(ML::AttrWarningOutOfBound, layout->LayoutSettings().GetWarningPiecesOutOfBound()); SetAttribute(ML::AttrWarningOutOfBound, layout->LayoutSettings().GetWarningPiecesOutOfBound());
SetAttribute(ML::AttrStickyEdges, layout->LayoutSettings().GetStickyEdges()); SetAttribute(ML::AttrStickyEdges, layout->LayoutSettings().GetStickyEdges());
SetAttribute(ML::AttrPiecesGap, layout->LayoutSettings().GetPiecesGap()); SetAttribute(ML::AttrPiecesGap, layout->LayoutSettings().GetPiecesGap());
// SetAttribute(ML::AttrFollowGrainLine, layout->LayoutSettings().GetFollowGrainline()); SetAttribute(ML::AttrFollowGrainline, layout->LayoutSettings().GetFollowGrainline());
writeEndElement(); // control writeEndElement(); // control
WriteTiles(layout); WriteTiles(layout);

View File

@ -73,7 +73,7 @@ const QString AttrRight = QStringLiteral("right");
const QString AttrBottom = QStringLiteral("bottom"); const QString AttrBottom = QStringLiteral("bottom");
const QString AttrWidth = QStringLiteral("width"); const QString AttrWidth = QStringLiteral("width");
const QString AttrLength = QStringLiteral("length"); const QString AttrLength = QStringLiteral("length");
const QString AttrFollowGrainLine = QStringLiteral("followGrainLine"); const QString AttrFollowGrainline = QStringLiteral("followGrainline");
const QString AttrID = QStringLiteral("id"); const QString AttrID = QStringLiteral("id");
const QString AttrMirrored = QStringLiteral("mirrored"); const QString AttrMirrored = QStringLiteral("mirrored");
const QString AttrTransform = QStringLiteral("transform"); const QString AttrTransform = QStringLiteral("transform");

View File

@ -78,7 +78,7 @@ extern const QString AttrRight;
extern const QString AttrBottom; extern const QString AttrBottom;
extern const QString AttrWidth; extern const QString AttrWidth;
extern const QString AttrLength; extern const QString AttrLength;
extern const QString AttrFollowGrainLine; extern const QString AttrFollowGrainline;
extern const QString AttrID; extern const QString AttrID;
extern const QString AttrMirrored; extern const QString AttrMirrored;
extern const QString AttrTransform; extern const QString AttrTransform;

View File

@ -27,6 +27,7 @@
<xs:attribute type="xs:boolean" name="warningSuperposition"/> <xs:attribute type="xs:boolean" name="warningSuperposition"/>
<xs:attribute type="xs:boolean" name="warningOutOfBound"/> <xs:attribute type="xs:boolean" name="warningOutOfBound"/>
<xs:attribute type="xs:boolean" name="stickyEdges"/> <xs:attribute type="xs:boolean" name="stickyEdges"/>
<xs:attribute type="xs:boolean" name="followGrainline"/>
<xs:attribute type="xs:float" name="piecesGap"/> <xs:attribute type="xs:float" name="piecesGap"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>