From 69df0922af4a939e2145cdd5eec9da3aba179be1 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Sat, 30 Mar 2019 11:17:54 +0200 Subject: [PATCH] Check timeout inside the layout generator. --HG-- branch : feature --- src/app/valentina/mainwindowsnogui.cpp | 68 +++++++++---------- src/libs/vlayout/vbank.cpp | 67 +++++++++++++++---- src/libs/vlayout/vbank.h | 7 +- src/libs/vlayout/vlayoutgenerator.cpp | 90 ++++++++++++++++++++++---- src/libs/vlayout/vlayoutgenerator.h | 5 +- src/libs/vlayout/vlayoutpaper.cpp | 8 ++- 6 files changed, 178 insertions(+), 67 deletions(-) diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp index 527bfcf24..859488d49 100644 --- a/src/app/valentina/mainwindowsnogui.cpp +++ b/src/app/valentina/mainwindowsnogui.cpp @@ -123,22 +123,6 @@ void InsertGlobalContours(const QList &scenes, const QListaddItem(gcontours.at(i)); } } - -//--------------------------------------------------------------------------------------------------------------------- -qreal BiggestEdge(const QVector &pieces) -{ - qreal edge = 0; - for(auto &piece : pieces) - { - const qreal pieceEdge = piece.BiggestEdge(); - if (pieceEdge > edge) - { - edge = pieceEdge; - } - } - - return edge; -} } //--------------------------------------------------------------------------------------------------------------------- @@ -231,7 +215,8 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) QTimer *progressTimer = nullptr; #endif - DialogLayoutProgress *progress = new DialogLayoutProgress(timer, lGenerator.GetNestingTime()*1000, this); + QScopedPointer progress(new DialogLayoutProgress(timer, lGenerator.GetNestingTime()*60000, + this)); if (VApplication::IsGUIMode()) { #if defined(Q_OS_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) @@ -241,23 +226,20 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) progressTimer = new QTimer(this); connect(progressTimer, &QTimer::timeout, this, [timer, &lGenerator]() { - const qint64 elapsed = timer.elapsed(); - const int timeout = static_cast(lGenerator.GetNestingTime() * 1000 - elapsed); - - m_taskbarProgress->setValue(static_cast(elapsed/1000)); + m_taskbarProgress->setValue(static_cast(timer.elapsed()/60000)); }); progressTimer->start(1000); #endif - connect(progress, &DialogLayoutProgress::Abort, &lGenerator, &VLayoutGenerator::Abort); + connect(progress.data(), &DialogLayoutProgress::Abort, &lGenerator, &VLayoutGenerator::Abort); } progress->Start(); LayoutErrors nestingState = LayoutErrors::NoError; - auto IsTimeout = [progress, &lGenerator, timer, &nestingState]() + auto IsTimeout = [&progress, &lGenerator, timer, &nestingState]() { - if (lGenerator.GetNestingTime() * 1000 - timer.elapsed() <= 0) + if (timer.hasExpired(lGenerator.GetNestingTime() * 60000)) { nestingState = LayoutErrors::Timeout; progress->Finished(); @@ -268,10 +250,13 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) bool rotationUsed = false; int rotatate = 1; - lGenerator.SetShift(BiggestEdge(listDetails) + 1); + lGenerator.SetShift(-1); // Trigger first shift calulation + lGenerator.SetRotate(false); int papersCount = INT_MAX; qreal efficiency = 0; + QCoreApplication::processEvents(); + forever { if (IsTimeout()) @@ -279,22 +264,20 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) break; } - lGenerator.Generate(); + lGenerator.Generate(timer, lGenerator.GetNestingTime()*60000); if (IsTimeout()) { break; } - nestingState = lGenerator.State(); - - switch (nestingState) + switch (lGenerator.State()) { case LayoutErrors::NoError: if (lGenerator.PapersCount() <= papersCount) { const qreal layoutEfficiency = lGenerator.LayoutEfficiency(); - if (efficiency > layoutEfficiency) + if (efficiency < layoutEfficiency) { efficiency = layoutEfficiency; progress->Efficiency(efficiency); @@ -320,27 +303,34 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) lGenerator.SetShift(lGenerator.GetShift()/2.0); break; case LayoutErrors::EmptyPaperError: - if (not rotationUsed) + if (lGenerator.IsRotationNeeded()) { - lGenerator.SetRotate(true); - lGenerator.SetRotationNumber(++rotatate); - rotationUsed = true; + if (not rotationUsed) + { + lGenerator.SetRotate(true); + lGenerator.SetRotationNumber(++rotatate); + rotationUsed = true; + } + else + { + lGenerator.SetShift(lGenerator.GetShift()/2.0); + rotationUsed = false; + } } else { lGenerator.SetShift(lGenerator.GetShift()/2.0); - rotationUsed = false; } break; case LayoutErrors::Timeout: - Q_UNREACHABLE(); - break; case LayoutErrors::PrepareLayoutError: case LayoutErrors::ProcessStoped: default: break; } + nestingState = lGenerator.State(); + if (nestingState == LayoutErrors::PrepareLayoutError || nestingState == LayoutErrors::ProcessStoped || (nestingState == LayoutErrors::NoError && not qFuzzyIsNull(lGenerator.GetEfficiencyCoefficient()) && efficiency >= lGenerator.GetEfficiencyCoefficient())) @@ -354,6 +344,8 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) } } + progress->Finished(); + #if defined(Q_OS_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) if (VApplication::IsGUIMode()) { @@ -367,7 +359,7 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) QApplication::alert(this); } - if (nestingState == LayoutErrors::NoError) + if (nestingState == LayoutErrors::NoError || (nestingState == LayoutErrors::Timeout && not papers.isEmpty())) { return true; } diff --git a/src/libs/vlayout/vbank.cpp b/src/libs/vlayout/vbank.cpp index 343bd0986..6cdf627be 100644 --- a/src/libs/vlayout/vbank.cpp +++ b/src/libs/vlayout/vbank.cpp @@ -176,7 +176,29 @@ void VBank::NotArranged(int i) } //--------------------------------------------------------------------------------------------------------------------- -bool VBank::Prepare() +bool VBank::PrepareUnsorted() +{ + for (int i=0; i < details.size(); ++i) + { + const qint64 square = details.at(i).Square(); + if (square <= 0) + { + qCCritical(lBank, "Preparing data for layout error: Detail '%s' square <= 0", + qUtf8Printable(details.at(i).GetName())); + prepare = false; + return prepare; + } + unsorted.insert(i, square); + } + + PrepareGroup(); + + prepare = true; + return prepare; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VBank::PrepareDetails() { if (layoutWidth <= 0) { @@ -193,10 +215,12 @@ bool VBank::Prepare() } diagonal = 0; + for (int i=0; i < details.size(); ++i) { details[i].SetLayoutWidth(layoutWidth); details[i].SetLayoutAllowancePoints(); + if (not details.at(i).IsLayoutAllowanceValid()) { const QString errorMsg = QObject::tr("Piece '%1' has invalid layout allowance. Please, check seam allowance" @@ -209,20 +233,8 @@ bool VBank::Prepare() { diagonal = d; } - - const qint64 square = details.at(i).Square(); - if (square <= 0) - { - qCCritical(lBank, "Preparing data for layout error: Detail '%s' square <= 0", - qUtf8Printable(details.at(i).GetName())); - prepare = false; - return prepare; - } - unsorted.insert(i, square); } - PrepareGroup(); - prepare = true; return prepare; } @@ -436,6 +448,35 @@ void VBank::SqMaxMin(qint64 &sMax, qint64 &sMin) const } +//--------------------------------------------------------------------------------------------------------------------- +qreal VBank::DetailsBiggestEdge() const +{ + qreal edge = 0; + for(auto &piece : details) + { + const qreal pieceEdge = piece.BiggestEdge(); + if (pieceEdge > edge) + { + edge = pieceEdge; + } + } + + return edge; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VBank::IsRotationNeeded() const +{ + for(auto &piece : details) + { + if (not piece.IsGrainlineEnabled()) + { + return true; + } + } + return false; +} + #if defined (Q_OS_WIN) && defined (Q_CC_MSVC) #pragma pop_macro("small") #endif diff --git a/src/libs/vlayout/vbank.h b/src/libs/vlayout/vbank.h index 85853770d..beee3479c 100644 --- a/src/libs/vlayout/vbank.h +++ b/src/libs/vlayout/vbank.h @@ -54,6 +54,7 @@ public: qreal GetLayoutWidth() const; void SetLayoutWidth(qreal value); + void SetDetails(const QVector &details); int GetNext(); VLayoutPiece GetDetail(int i) const; @@ -61,7 +62,8 @@ public: void Arranged(int i); void NotArranged(int i); - bool Prepare(); + bool PrepareUnsorted(); + bool PrepareDetails(); void Reset(); void SetCaseType(Cases caseType); @@ -70,6 +72,9 @@ public: int ArrangedCount() const; qreal GetBiggestDiagonal() const; + qreal DetailsBiggestEdge() const; + + bool IsRotationNeeded() const; private: Q_DISABLE_COPY(VBank) diff --git a/src/libs/vlayout/vlayoutgenerator.cpp b/src/libs/vlayout/vlayoutgenerator.cpp index 766a3925f..dad17c4b9 100644 --- a/src/libs/vlayout/vlayoutgenerator.cpp +++ b/src/libs/vlayout/vlayoutgenerator.cpp @@ -28,6 +28,7 @@ #include "vlayoutgenerator.h" +#include #include #include #include @@ -98,21 +99,25 @@ int VLayoutGenerator::DetailsCount() } //--------------------------------------------------------------------------------------------------------------------- -void VLayoutGenerator::Generate() +void VLayoutGenerator::Generate(QElapsedTimer timer, qint64 timeout) { stopGeneration.store(false); papers.clear(); + bank->Reset(); state = LayoutErrors::NoError; -#ifdef LAYOUT_DEBUG - const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug"); - QDir debugDir(path); - debugDir.removeRecursively(); - debugDir.mkpath(path); -#endif - - if (bank->Prepare()) + if (VFuzzyComparePossibleNulls(shift, -1)) { + if (bank->PrepareDetails()) + { + SetShift(bank->DetailsBiggestEdge() + 1); + } + else + { + state = LayoutErrors::PrepareLayoutError; + return; + } + int width = PageWidth(); int height = PageHeight(); @@ -131,15 +136,43 @@ void VLayoutGenerator::Generate() IsPortrait() ? SetStrip(height) : SetStrip(width); } + } + + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; + } + +#ifdef LAYOUT_DEBUG + const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug"); + QDir debugDir(path); + debugDir.removeRecursively(); + debugDir.mkpath(path); +#endif + + if (bank->PrepareUnsorted()) + { + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; + } while (bank->AllDetailsCount() > 0) { if (stopGeneration.load()) { - break; + return; } - VLayoutPaper paper(height, width, bank->GetLayoutWidth()); + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; + } + + VLayoutPaper paper(PageHeight(), PageWidth(), bank->GetLayoutWidth()); paper.SetShift(shift); paper.SetPaperIndex(static_cast(papers.count())); paper.SetRotate(rotate); @@ -158,15 +191,29 @@ void VLayoutGenerator::Generate() bank->NotArranged(index); } + QCoreApplication::processEvents(); + if (stopGeneration.load()) { break; } + + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; + } } while(bank->LeftToArrange() > 0); if (stopGeneration.load()) { - break; + return; + } + + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; } if (paper.Count() > 0) @@ -186,6 +233,12 @@ void VLayoutGenerator::Generate() return; } + if (timer.hasExpired(timeout)) + { + state = LayoutErrors::Timeout; + return; + } + if (stripOptimizationEnabled) { GatherPages(); @@ -295,6 +348,19 @@ void VLayoutGenerator::SetTextAsPaths(bool value) textAsPaths = value; } +//--------------------------------------------------------------------------------------------------------------------- +bool VLayoutGenerator::IsRotationNeeded() const +{ + if (followGrainline) + { + return bank->IsRotationNeeded(); + } + else + { + return true; + } +} + //--------------------------------------------------------------------------------------------------------------------- quint8 VLayoutGenerator::GetMultiplier() const { diff --git a/src/libs/vlayout/vlayoutgenerator.h b/src/libs/vlayout/vlayoutgenerator.h index 14f35cd3e..e894cd982 100644 --- a/src/libs/vlayout/vlayoutgenerator.h +++ b/src/libs/vlayout/vlayoutgenerator.h @@ -52,6 +52,7 @@ class QMarginsF; class QGraphicsItem; class VLayoutPaper; +class QElapsedTimer; class VLayoutGenerator :public QObject { @@ -84,7 +85,7 @@ public: qreal GetShift() const; void SetShift(qreal shift); - void Generate(); + void Generate(QElapsedTimer timer, qint64 timeout); qreal LayoutEfficiency() const; @@ -125,6 +126,8 @@ public: bool IsTestAsPaths() const; void SetTextAsPaths(bool value); + bool IsRotationNeeded() const; + public slots: void Abort(); diff --git a/src/libs/vlayout/vlayoutpaper.cpp b/src/libs/vlayout/vlayoutpaper.cpp index 8df587928..f3329bda5 100644 --- a/src/libs/vlayout/vlayoutpaper.cpp +++ b/src/libs/vlayout/vlayoutpaper.cpp @@ -240,6 +240,8 @@ bool VLayoutPaper::AddToSheet(const VLayoutPiece &detail, std::atomic_bool &stop for (int j=1; j <= d->globalContour.GlobalEdgesCount(); ++j) { + QCoreApplication::processEvents(); + for (int i=1; i<= detailEdgesCount; ++i) { VPositionData data; @@ -431,8 +433,10 @@ qreal VLayoutPaper::Efficiency() const qreal efficiency = 0; for(auto &detail : d->details) { - efficiency += detail.Square(); + efficiency += static_cast(detail.Square()); } - return efficiency / (d->globalContour.GetWidth() * d->globalContour.GetHeight()) * 100; + const QRectF boundingRect = DetailsBoundingRect(); + + return efficiency / (boundingRect.width() * boundingRect.height()) * 100.0; }