Move piece position validation to separate thread.

This commit is contained in:
Roman Telezhynskyi 2024-04-20 17:00:51 +03:00
parent a8a75f358a
commit 537efbeaa8
7 changed files with 357 additions and 244 deletions

View File

@ -276,7 +276,7 @@ auto VPLayout::AddSheet(const VPSheetPtr &sheet) -> VPSheetPtr
if (not sheet.isNull() && GetSheet(sheet->Uuid()).isNull()) if (not sheet.isNull() && GetSheet(sheet->Uuid()).isNull())
{ {
m_sheets.append(sheet); m_sheets.append(sheet);
connect(this, &VPLayout::PieceTransformationChanged, sheet.data(), &VPSheet::CheckPiecePositionValidity); connect(this, &VPLayout::PieceTransformationChanged, sheet.data(), &VPSheet::CheckPiecesPositionValidity);
} }
return sheet; return sheet;
} }
@ -328,7 +328,7 @@ void VPLayout::SetFocusedSheet(const VPSheetPtr &focusedSheet)
m_focusedSheet = focusedSheet.isNull() ? m_sheets.constFirst() : focusedSheet; m_focusedSheet = focusedSheet.isNull() ? m_sheets.constFirst() : focusedSheet;
} }
CheckPiecesPositionValidity(m_focusedSheet); m_focusedSheet->CheckPiecesPositionValidity();
emit ActiveSheetChanged(m_focusedSheet); emit ActiveSheetChanged(m_focusedSheet);
} }
@ -427,30 +427,9 @@ void VPLayout::CheckPiecesPositionValidity() const
{ {
for (const auto &sheet : m_sheets) for (const auto &sheet : m_sheets)
{ {
CheckPiecesPositionValidity(sheet);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPLayout::CheckPiecesPositionValidity(const VPSheetPtr &sheet) const
{
if (not sheet.isNull()) if (not sheet.isNull())
{ {
const VPLayoutSettings &settings = LayoutSettings(); sheet->CheckPiecesPositionValidity();
if (settings.GetWarningPiecesOutOfBound())
{
sheet->ValidatePiecesOutOfBound();
}
if (settings.GetWarningSuperpositionOfPieces())
{
sheet->ValidateSuperpositionOfPieces();
}
if (settings.GetWarningPieceGapePosition())
{
sheet->ValidatePieceGapePosition();
} }
} }
} }

View File

@ -91,7 +91,6 @@ public:
void Clear(); void Clear();
void CheckPiecesPositionValidity() const; void CheckPiecesPositionValidity() const;
void CheckPiecesPositionValidity(const VPSheetPtr &sheet) const;
auto TileFactory() const -> QSharedPointer<VPTileFactory>; auto TileFactory() const -> QSharedPointer<VPTileFactory>;
void SetTileFactory(const QSharedPointer<VPTileFactory> &newTileFactory); void SetTileFactory(const QSharedPointer<VPTileFactory> &newTileFactory);

View File

@ -62,7 +62,7 @@ namespace
{ {
constexpr qreal minStickyDistance = MmToPixel(3.); constexpr qreal minStickyDistance = MmToPixel(3.);
constexpr qreal maxStickyDistance = MmToPixel(15.); constexpr qreal maxStickyDistance = MmToPixel(15.);
constexpr qreal stickyShift = MmToPixel(1.); constexpr qreal stickyShift = MmToPixel(5.);
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto CutEdge(const QLineF &edge) -> QVector<QPointF> auto CutEdge(const QLineF &edge) -> QVector<QPointF>
@ -440,24 +440,15 @@ auto VPPiece::PrepareStickyPath(const QVector<QPointF> &path) -> QVector<QPointF
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPPiece::ClosestDistance(const QVector<QPointF> &path1, const QVector<QPointF> &path2) -> QLineF auto VPPiece::ClosestDistance(const QVector<QPointF> &path1, const QVector<QPointF> &path2) -> QLineF
{ {
std::function<QLineF(const QPointF &)> const DistanceFunc = [path2](const QPointF &p1) const int maxThreads = QThread::idealThreadCount();
{
qreal minLocalDistance = std::numeric_limits<qreal>::max();
QLineF localClosestDistance;
for (const auto &p2 : path2) QVector<QVector<QPointF>> path1Chunks;
path1Chunks.reserve(maxThreads);
const vsizetype chunkSize = (path1.size() + maxThreads - 1) / maxThreads; // Round up
for (vsizetype i = 0; i < path1.size(); i += chunkSize)
{ {
QLineF const d(p1, p2); path1Chunks.append(path1.mid(i, chunkSize));
qreal const length = d.length();
if (length < minLocalDistance)
{
minLocalDistance = length;
localClosestDistance = d;
} }
}
return localClosestDistance;
};
std::function<void(QLineF &, const QLineF &)> const ReduceFunc = [](QLineF &result, const QLineF &next) std::function<void(QLineF &, const QLineF &)> const ReduceFunc = [](QLineF &result, const QLineF &next)
{ {
@ -469,7 +460,29 @@ auto VPPiece::ClosestDistance(const QVector<QPointF> &path1, const QVector<QPoin
} }
}; };
return QtConcurrent::blockingMappedReduced<QLineF>(path1, DistanceFunc, ReduceFunc); auto CalculateClosestDistanceForChunk = [&](const QVector<QPointF> &chunk) -> QLineF
{
qreal minLocalDistance = std::numeric_limits<qreal>::max();
QLineF localClosestDistance;
for (const auto &c : chunk)
{
for (const auto &p2 : path2)
{
QLineF const d(c, p2);
qreal const length = d.length();
if (length < minLocalDistance)
{
minLocalDistance = length;
localClosestDistance = d;
}
}
}
return localClosestDistance;
};
return QtConcurrent::blockingMappedReduced<QLineF>(path1Chunks, CalculateClosestDistanceForChunk, ReduceFunc);
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -38,6 +38,205 @@
#include "vplayout.h" #include "vplayout.h"
#include "vppiece.h" #include "vppiece.h"
#include <QtConcurrent>
namespace
{
struct VSheetPiece
{
QString m_id{};
bool m_showFullPiece{false};
QLineF m_seamMirrorLine{};
QLineF m_seamAllowanceMirrorLine{};
QVector<QPointF> m_externalContourPoints{};
};
struct VPiecesValidationData
{
bool m_warnPiecesOutOfBound{false};
bool m_warnSuperpositionOfPieces{false};
bool m_warnPieceGapePosition{false};
bool m_cutOnFold{false};
QRectF m_sheetRect{};
qreal m_pieceGap{0};
QVector<VSheetPiece> m_pieces{};
};
//---------------------------------------------------------------------------------------------------------------------
void ValidatePiecesOutOfBound(const VPiecesValidationData &data, QHash<QString, VPiecePositionValidity> &validations)
{
for (const auto &piece : data.m_pieces)
{
VPiecePositionValidity validation = validations.value(piece.m_id);
if (data.m_cutOnFold && not piece.m_showFullPiece && !piece.m_seamMirrorLine.isNull())
{
QLineF const foldLine = data.m_sheetRect.width() >= data.m_sheetRect.height()
? QLineF(data.m_sheetRect.topLeft(), data.m_sheetRect.topRight())
: QLineF(data.m_sheetRect.topRight(), data.m_sheetRect.bottomRight());
validation.m_outOfBound =
not VGObject::IsLineSegmentOnLineSegment(foldLine, piece.m_seamAllowanceMirrorLine, MmToPixel(0.5));
}
else
{
QRectF const pieceRect = VLayoutPiece::BoundingRect(piece.m_externalContourPoints);
validation.m_outOfBound = not data.m_sheetRect.contains(pieceRect);
}
validations.insert(piece.m_id, validation);
}
}
//---------------------------------------------------------------------------------------------------------------------
void ValidateSuperpositionOfPieces(const VPiecesValidationData &data,
QHash<QString, VPiecePositionValidity> &validations)
{
QSet<QString> invalidPieces;
invalidPieces.reserve(data.m_pieces.size());
for (const auto &piece : data.m_pieces)
{
if (invalidPieces.contains(piece.m_id))
{
continue;
}
bool hasSuperposition = false;
VSheetPiece invalidPiece;
for (const auto &p : data.m_pieces)
{
if (piece.m_id == p.m_id)
{
continue;
}
if (VPPiece::PathsSuperposition(piece.m_externalContourPoints, p.m_externalContourPoints))
{
hasSuperposition = true;
invalidPiece = p;
break;
}
}
auto UpdateValidity = [&validations, hasSuperposition, &invalidPieces](const QString &id)
{
VPiecePositionValidity validation = validations.value(id);
validation.m_superposition = hasSuperposition;
validations.insert(id, validation);
if (hasSuperposition)
{
invalidPieces.insert(id);
}
};
UpdateValidity(piece.m_id);
if (!invalidPiece.m_id.isEmpty())
{
UpdateValidity(invalidPiece.m_id);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void ValidatePiecesGapePosition(const VPiecesValidationData &data, QHash<QString, VPiecePositionValidity> &validations)
{
if (data.m_pieceGap <= 0)
{
return;
}
QSet<QString> invalidPieces;
invalidPieces.reserve(data.m_pieces.size());
for (const auto &piece : data.m_pieces)
{
if (invalidPieces.contains(piece.m_id))
{
continue;
}
QRectF const path1Rect = VLayoutPiece::BoundingRect(piece.m_externalContourPoints)
.adjusted(-data.m_pieceGap, -data.m_pieceGap, data.m_pieceGap, data.m_pieceGap);
QVector<QPointF> const path1 = VPPiece::PrepareStickyPath(piece.m_externalContourPoints);
bool hasInvalidPieceGapPosition = false;
VSheetPiece invalidPiece;
for (const auto &p : data.m_pieces)
{
if (piece.m_id == p.m_id)
{
continue;
}
QRectF const path2Rect =
VLayoutPiece::BoundingRect(p.m_externalContourPoints)
.adjusted(-data.m_pieceGap, -data.m_pieceGap, data.m_pieceGap, data.m_pieceGap);
if (!path1Rect.intersects(path2Rect) && !path1Rect.contains(path2Rect) && !path2Rect.contains(path1Rect))
{
continue;
}
QVector<QPointF> const path2 = VPPiece::PrepareStickyPath(p.m_externalContourPoints);
QLineF const distance = VPPiece::ClosestDistance(path1, path2);
if (distance.length() < data.m_pieceGap - accuracyPointOnLine)
{
hasInvalidPieceGapPosition = true;
invalidPiece = p;
break;
}
}
auto UpdateValidity = [&validations, hasInvalidPieceGapPosition, &invalidPieces](const QString &id)
{
VPiecePositionValidity validation = validations.value(id);
validation.m_gap = hasInvalidPieceGapPosition;
validations.insert(id, validation);
if (hasInvalidPieceGapPosition)
{
invalidPieces.insert(id);
}
};
UpdateValidity(piece.m_id);
if (!invalidPiece.m_id.isEmpty())
{
UpdateValidity(invalidPiece.m_id);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
auto ValidatePiecesPositions(const VPiecesValidationData &data) -> QHash<QString, VPiecePositionValidity>
{
QHash<QString, VPiecePositionValidity> validations;
if (data.m_warnPiecesOutOfBound)
{
ValidatePiecesOutOfBound(data, validations);
}
if (data.m_warnSuperpositionOfPieces)
{
ValidateSuperpositionOfPieces(data, validations);
}
if (data.m_warnPieceGapePosition)
{
ValidatePiecesGapePosition(data, validations);
}
return validations;
}
} // namespace
// VPSheetSceneData // VPSheetSceneData
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPSheetSceneData::VPSheetSceneData(const VPLayoutPtr &layout, const QUuid &sheetUuid) VPSheetSceneData::VPSheetSceneData(const VPLayoutPtr &layout, const QUuid &sheetUuid)
@ -339,7 +538,8 @@ void VPSheetSceneData::ConnectPiece(VPGraphicsPiece *piece) const
VPSheet::VPSheet(const VPLayoutPtr &layout, QObject *parent) VPSheet::VPSheet(const VPLayoutPtr &layout, QObject *parent)
: QObject(parent), : QObject(parent),
m_layout(layout), m_layout(layout),
m_sceneData(QSharedPointer<VPSheetSceneData>::create(layout, Uuid())) m_sceneData(QSharedPointer<VPSheetSceneData>::create(layout, Uuid())),
m_validityWatcher(new QFutureWatcher<QHash<QString, VPiecePositionValidity>>(this))
{ {
SCASSERT(not layout.isNull()) SCASSERT(not layout.isNull())
@ -347,10 +547,16 @@ VPSheet::VPSheet(const VPLayoutPtr &layout, QObject *parent)
SetIgnoreMargins(settings->GetLayoutSheetIgnoreMargins()); SetIgnoreMargins(settings->GetLayoutSheetIgnoreMargins());
SetSheetMargins(settings->GetLayoutSheetMargins()); SetSheetMargins(settings->GetLayoutSheetMargins());
SetSheetSize(QSizeF(settings->GetLayoutSheetPaperWidth(), settings->GetLayoutSheetPaperHeight())); SetSheetSize(QSizeF(settings->GetLayoutSheetPaperWidth(), settings->GetLayoutSheetPaperHeight()));
connect(m_validityWatcher, &QFutureWatcher<QHash<QString, VPiecePositionValidity>>::finished, this,
&VPSheet::UpdatePiecesValidity);
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VPSheet::~VPSheet() = default; VPSheet::~VPSheet()
{
m_validityWatcher->cancel();
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPSheet::GetLayout() const -> VPLayoutPtr auto VPSheet::GetLayout() const -> VPLayoutPtr
@ -508,171 +714,6 @@ void VPSheet::SetTrashSheet(bool newTrashSheet)
m_trashSheet = newTrashSheet; m_trashSheet = newTrashSheet;
} }
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::ValidateSuperpositionOfPieces() const
{
QList<VPPiecePtr> const pieces = GetPieces();
for (const auto &piece : pieces)
{
if (piece.isNull() || piece->OutOfBound())
{
continue;
}
const bool oldSuperpositionOfPieces = piece->HasSuperpositionWithPieces();
QVector<QPointF> path1;
CastTo(piece->GetMappedExternalContourPoints(), path1);
bool hasSuperposition = false;
for (const auto &p : pieces)
{
if (p.isNull() || piece == p)
{
continue;
}
QVector<QPointF> path2;
CastTo(p->GetMappedExternalContourPoints(), path2);
bool const superposition = VPPiece::PathsSuperposition(path1, path2);
if (superposition)
{
hasSuperposition = superposition;
break;
}
}
piece->SetHasSuperpositionWithPieces(hasSuperposition);
if (oldSuperpositionOfPieces != piece->HasSuperpositionWithPieces())
{
VPLayoutPtr const layout = GetLayout();
if (not layout.isNull())
{
emit layout->PiecePositionValidityChanged(piece);
}
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::ValidatePieceGapePosition(const VPPiecePtr &piece) const
{
VPLayoutPtr const layout = GetLayout();
if (layout.isNull())
{
return;
}
const qreal pieceGap = layout->LayoutSettings().GetPiecesGap();
if (pieceGap <= 0)
{
return;
}
if (piece.isNull() || piece->HasSuperpositionWithPieces() || piece->OutOfBound())
{
return;
}
const bool oldInvalidPieceGapPosition = piece->HasInvalidPieceGapPosition();
QVector<QPointF> path1;
CastTo(piece->GetMappedExternalContourPoints(), path1);
path1 = VPPiece::PrepareStickyPath(path1);
bool hasInvalidPieceGapPosition = false;
QList<VPPiecePtr> const pieces = GetPieces();
for (const auto &p : pieces)
{
if (p.isNull() || piece == p)
{
continue;
}
QVector<QPointF> path2;
CastTo(p->GetMappedExternalContourPoints(), path2);
path2 = VPPiece::PrepareStickyPath(path2);
QLineF const distance = VPPiece::ClosestDistance(path1, path2);
if (distance.length() < pieceGap - accuracyPointOnLine)
{
hasInvalidPieceGapPosition = true;
break;
}
}
piece->SetHasInvalidPieceGapPosition(hasInvalidPieceGapPosition);
if (oldInvalidPieceGapPosition != piece->HasInvalidPieceGapPosition())
{
VPLayoutPtr const layout = GetLayout();
if (not layout.isNull())
{
emit layout->PiecePositionValidityChanged(piece);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::ValidatePieceGapePosition() const
{
QList<VPPiecePtr> const pieces = GetPieces();
for (const auto &piece : pieces)
{
ValidatePieceGapePosition(piece);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::ValidatePieceOutOfBound(const VPPiecePtr &piece) const
{
if (piece.isNull())
{
return;
}
const bool oldOutOfBound = piece->OutOfBound();
QRectF const sheetRect = GetMarginsRect();
VPLayoutPtr const layout = GetLayout();
if (not layout.isNull() && layout->LayoutSettings().IsCutOnFold() && not piece->IsShowFullPiece() &&
!piece->GetSeamMirrorLine().isNull())
{
QLineF const foldLine = sheetRect.width() >= sheetRect.height()
? QLineF(sheetRect.topLeft(), sheetRect.topRight())
: QLineF(sheetRect.topRight(), sheetRect.bottomRight());
piece->SetOutOfBound(not VGObject::IsLineSegmentOnLineSegment(
foldLine, piece->GetMappedSeamAllowanceMirrorLine(), MmToPixel(0.5)));
}
else
{
QRectF const pieceRect = piece->MappedDetailBoundingRect();
piece->SetOutOfBound(not sheetRect.contains(pieceRect));
}
if (oldOutOfBound != piece->OutOfBound())
{
if (not layout.isNull())
{
emit layout->PiecePositionValidityChanged(piece);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::ValidatePiecesOutOfBound() const
{
QList<VPPiecePtr> const pieces = GetPieces();
for (const auto &piece : pieces)
{
ValidatePieceOutOfBound(piece);
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPSheet::GetSheetRect() const -> QRectF auto VPSheet::GetSheetRect() const -> QRectF
{ {
@ -752,32 +793,91 @@ void VPSheet::RemoveUnusedLength()
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPSheet::CheckPiecePositionValidity(const VPPiecePtr &piece) const void VPSheet::CheckPiecesPositionValidity() const
{ {
if (m_validityWatcher->isFinished())
{
VPLayoutPtr const layout = GetLayout(); VPLayoutPtr const layout = GetLayout();
if (layout.isNull()) if (layout.isNull())
{ {
return; return;
} }
if (QList<VPPiecePtr> const pieces = GetPieces(); piece.isNull() || not pieces.contains(piece)) VPiecesValidationData data;
data.m_warnPiecesOutOfBound = layout->LayoutSettings().GetWarningPiecesOutOfBound();
data.m_warnSuperpositionOfPieces = layout->LayoutSettings().GetWarningSuperpositionOfPieces();
data.m_warnPieceGapePosition = layout->LayoutSettings().GetWarningPieceGapePosition();
data.m_cutOnFold = layout->LayoutSettings().IsCutOnFold();
data.m_sheetRect = GetMarginsRect();
data.m_pieceGap = layout->LayoutSettings().GetPiecesGap();
QList<VPPiecePtr> const pieces = GetPieces();
QVector<VSheetPiece> sheetPieces;
sheetPieces.reserve(pieces.size());
for (const auto &piece : pieces)
{
VSheetPiece data;
data.m_showFullPiece = piece->IsShowFullPiece();
data.m_id = piece->GetUniqueID();
data.m_seamMirrorLine = piece->GetMappedSeamMirrorLine();
data.m_seamAllowanceMirrorLine = piece->GetMappedSeamAllowanceMirrorLine();
QVector<QPointF> points;
CastTo(piece->GetMappedExternalContourPoints(), points);
data.m_externalContourPoints = points;
sheetPieces.append(data);
}
data.m_pieces = sheetPieces;
m_validationStale = false;
m_validityWatcher->setFuture(QtConcurrent::run([data]() { return ValidatePiecesPositions(data); }));
}
else
{
m_validationStale = true;
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPSheet::UpdatePiecesValidity()
{
QHash<QString, VPiecePositionValidity> const newValidations = m_validityWatcher->future().result();
QList<VPPiecePtr> const pieces = GetPieces();
QHash<QString, VPPiecePtr> sortedPieces;
sortedPieces.reserve(pieces.size());
for (const auto &piece : pieces)
{
sortedPieces.insert(piece->GetUniqueID(), piece);
}
VPLayoutPtr const layout = GetLayout();
if (layout.isNull())
{ {
return; return;
} }
if (layout->LayoutSettings().GetWarningPiecesOutOfBound()) for (auto i = newValidations.cbegin(), end = newValidations.cend(); i != end; ++i)
{ {
ValidatePieceOutOfBound(piece); if (sortedPieces.contains(i.key()))
{
VPPiecePtr const piece = sortedPieces.value(i.key());
piece->SetOutOfBound(i.value().m_outOfBound);
piece->SetHasSuperpositionWithPieces(i.value().m_superposition);
piece->SetHasInvalidPieceGapPosition(i.value().m_gap);
emit layout->PiecePositionValidityChanged(piece);
}
} }
if (layout->LayoutSettings().GetWarningSuperpositionOfPieces()) if (m_validationStale)
{ {
ValidateSuperpositionOfPieces(); m_validationStale = false;
} CheckPiecesPositionValidity();
if (layout->LayoutSettings().GetWarningPieceGapePosition())
{
ValidatePieceGapePosition(piece);
} }
} }

View File

@ -29,6 +29,7 @@
#define VPSHEET_H #define VPSHEET_H
#include <QComboBox> #include <QComboBox>
#include <QFutureWatcher>
#include <QList> #include <QList>
#include <QMarginsF> #include <QMarginsF>
#include <QPageLayout> #include <QPageLayout>
@ -50,6 +51,13 @@ class VPGraphicsSheet;
class VLayoutPiece; class VLayoutPiece;
class QGraphicsItem; class QGraphicsItem;
struct VPiecePositionValidity
{
bool m_outOfBound{false};
bool m_superposition{false};
bool m_gap{false};
};
class VPSheetSceneData class VPSheetSceneData
{ {
public: public:
@ -183,12 +191,6 @@ public:
auto TrashSheet() const -> bool; auto TrashSheet() const -> bool;
void SetTrashSheet(bool newTrashSheet); void SetTrashSheet(bool newTrashSheet);
void ValidateSuperpositionOfPieces() const;
void ValidatePieceGapePosition(const VPPiecePtr &piece) const;
void ValidatePieceGapePosition() const;
void ValidatePieceOutOfBound(const VPPiecePtr &piece) const;
void ValidatePiecesOutOfBound() const;
auto GetSheetRect() const -> QRectF; auto GetSheetRect() const -> QRectF;
auto GetMarginsRect() const -> QRectF; auto GetMarginsRect() const -> QRectF;
@ -283,7 +285,10 @@ public:
auto GetSheetOrientation() const -> QPageLayout::Orientation; auto GetSheetOrientation() const -> QPageLayout::Orientation;
public slots: public slots:
void CheckPiecePositionValidity(const VPPiecePtr &piece) const; void CheckPiecesPositionValidity() const;
private slots:
void UpdatePiecesValidity();
private: private:
Q_DISABLE_COPY_MOVE(VPSheet) // NOLINT Q_DISABLE_COPY_MOVE(VPSheet) // NOLINT
@ -316,6 +321,9 @@ private:
QSharedPointer<VPSheetSceneData> m_sceneData{nullptr}; QSharedPointer<VPSheetSceneData> m_sceneData{nullptr};
QFutureWatcher<QHash<QString, VPiecePositionValidity>> *m_validityWatcher;
mutable bool m_validationStale{false};
auto SheetUnits() const -> Unit; auto SheetUnits() const -> Unit;
}; };

View File

@ -650,9 +650,7 @@ void VPMainGraphicsView::RemovePiece() const
if (not layout.isNull()) if (not layout.isNull())
{ {
emit layout->PieceSelectionChanged(piece); emit layout->PieceSelectionChanged(piece);
layout->UndoStack()->push(new VPUndoMovePieceOnSheet(VPSheetPtr(), piece));
auto *command = new VPUndoMovePieceOnSheet(VPSheetPtr(), piece);
layout->UndoStack()->push(command);
} }
} }
} }

View File

@ -1119,7 +1119,7 @@ void VPMainWindow::InitMarginsData(const QString &suffix)
LayoutWasSaved(false); LayoutWasSaved(false);
m_layout->TileFactory()->RefreshTileInfos(); m_layout->TileFactory()->RefreshTileInfos();
m_graphicsView->RefreshLayout(); m_graphicsView->RefreshLayout();
m_layout->CheckPiecesPositionValidity(sheet); sheet->CheckPiecesPositionValidity();
} }
} }
}); });
@ -2140,7 +2140,10 @@ void VPMainWindow::SheetPaperSizeChanged()
} }
else else
{ {
m_layout->CheckPiecesPositionValidity(m_layout->GetFocusedSheet()); if (VPSheetPtr sheet = m_layout->GetFocusedSheet(); !sheet.isNull())
{
sheet->CheckPiecesPositionValidity();
}
} }
} }
@ -3908,7 +3911,7 @@ void VPMainWindow::on_SheetMarginChanged()
LayoutWasSaved(false); LayoutWasSaved(false);
m_layout->CheckPiecesPositionValidity(sheet); sheet->CheckPiecesPositionValidity();
} }
m_graphicsView->RefreshLayout(); m_graphicsView->RefreshLayout();
@ -4910,7 +4913,10 @@ void VPMainWindow::LayoutWarningPieceGapePosition_toggled(bool checked)
LayoutWasSaved(false); LayoutWasSaved(false);
if (checked) if (checked)
{ {
m_layout->CheckPiecesPositionValidity(m_layout->GetFocusedSheet()); if (VPSheetPtr sheet = m_layout->GetFocusedSheet(); !sheet.isNull())
{
sheet->CheckPiecesPositionValidity();
}
} }
m_graphicsView->RefreshPieces(); m_graphicsView->RefreshPieces();
} }
@ -4925,7 +4931,11 @@ void VPMainWindow::LayoutWarningPiecesSuperposition_toggled(bool checked)
LayoutWasSaved(false); LayoutWasSaved(false);
if (checked) if (checked)
{ {
m_layout->CheckPiecesPositionValidity(m_layout->GetFocusedSheet());
if (VPSheetPtr sheet = m_layout->GetFocusedSheet(); !sheet.isNull())
{
sheet->CheckPiecesPositionValidity();
}
} }
m_graphicsView->RefreshPieces(); m_graphicsView->RefreshPieces();
} }
@ -4941,7 +4951,10 @@ void VPMainWindow::LayoutWarningPiecesOutOfBound_toggled(bool checked)
if (checked) if (checked)
{ {
m_layout->CheckPiecesPositionValidity(m_layout->GetFocusedSheet()); if (VPSheetPtr sheet = m_layout->GetFocusedSheet(); !sheet.isNull())
{
sheet->CheckPiecesPositionValidity();
}
} }
m_graphicsView->RefreshPieces(); m_graphicsView->RefreshPieces();
} }
@ -4954,7 +4967,10 @@ void VPMainWindow::LayoutCutOnFold_toggled(bool checked)
{ {
m_layout->LayoutSettings().SetCutOnFold(checked); m_layout->LayoutSettings().SetCutOnFold(checked);
LayoutWasSaved(false); LayoutWasSaved(false);
m_layout->CheckPiecesPositionValidity(m_layout->GetFocusedSheet()); if (VPSheetPtr sheet = m_layout->GetFocusedSheet(); !sheet.isNull())
{
sheet->CheckPiecesPositionValidity();
}
m_graphicsView->RefreshLayout(); m_graphicsView->RefreshLayout();
} }
} }