Move piece position validation to separate thread.
This commit is contained in:
parent
a8a75f358a
commit
537efbeaa8
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user