From 4041f9e154141f51f867154e5c80687723723ba4 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Thu, 26 Nov 2020 19:10:09 +0200 Subject: [PATCH] Restore layout debug system. --- src/app/valentina/mainwindowsnogui.cpp | 11 +- src/libs/vlayout/vlayoutdef.h | 22 +++ src/libs/vlayout/vlayoutpaper.cpp | 28 +++- src/libs/vlayout/vlayoutpaper.h | 7 +- src/libs/vlayout/vposition.cpp | 198 +++++++++++++++++++++++++ src/libs/vlayout/vposition.h | 13 ++ 6 files changed, 276 insertions(+), 3 deletions(-) diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp index 5333b149c..1dd20d403 100644 --- a/src/app/valentina/mainwindowsnogui.cpp +++ b/src/app/valentina/mainwindowsnogui.cpp @@ -293,6 +293,13 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) QCoreApplication::processEvents(); +#ifdef LAYOUT_DEBUG + const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug"); + QDir debugDir(path); + debugDir.removeRecursively(); + debugDir.mkpath(path); +#endif + forever { if (IsTimeout()) @@ -307,7 +314,9 @@ bool MainWindowsNoGUI::GenerateLayout(VLayoutGenerator& lGenerator) break; } - switch (lGenerator.State()) + nestingState = lGenerator.State(); + + switch (nestingState) { case LayoutErrors::NoError: if (lGenerator.PapersCount() <= papersCount) diff --git a/src/libs/vlayout/vlayoutdef.h b/src/libs/vlayout/vlayoutdef.h index cd213cacb..81049cf3b 100644 --- a/src/libs/vlayout/vlayoutdef.h +++ b/src/libs/vlayout/vlayoutdef.h @@ -115,4 +115,26 @@ struct VCachedPositions QPainterPath layoutAllowancePath{}; }; +/* Warning! Debugging doesn't work stable in debug mode. If you need big allocation use release mode. Or disable + * Address Sanitizer. See page https://bitbucket.org/dismine/valentina/wiki/developers/Address_Sanitizer + */ +//#define LAYOUT_DEBUG // Enable debug mode + +// This block help rule debug mode. Don't turn all options at the same time! +#ifdef LAYOUT_DEBUG +// Nice looking +# define SHOW_VERTICES // Show contour vertices +# define SHOW_DIRECTION // Show contour direction +# define ARRANGED_DETAILS // Show already arranged details +# define SHOW_SHEET // Show sheet rect +# define SHOW_CANDIDATE // Show each position + +// Debugging +//# define SHOW_ROTATION // For each position show rotation part +//# define SHOW_COMBINE // For each position show edge combine part +//# define SHOW_MIRROR // For each position show mirror part +//# define SHOW_CANDIDATE_BEST // For only correct positions that pass checks +# define SHOW_BEST // Show only best position for workpiece +#endif//LAYOUT_DEBUG + #endif // VLAYOUTDEF_H diff --git a/src/libs/vlayout/vlayoutpaper.cpp b/src/libs/vlayout/vlayoutpaper.cpp index 364436c14..59761af8e 100644 --- a/src/libs/vlayout/vlayoutpaper.cpp +++ b/src/libs/vlayout/vlayoutpaper.cpp @@ -43,6 +43,10 @@ #include #include +#ifdef LAYOUT_DEBUG +#include +#endif + #include "vbestsquare.h" #include "vcontour.h" #include "vlayoutpiece.h" @@ -239,6 +243,10 @@ bool VLayoutPaper::ArrangeDetail(const VLayoutPiece &detail, std::atomic_bool &s d->localRotationNumber = d->globalRotationNumber; } +#ifdef LAYOUT_DEBUG + QMutex mutex; +#endif + VPositionData data; data.gContour = d->globalContour; data.detail = detail; @@ -247,9 +255,17 @@ bool VLayoutPaper::ArrangeDetail(const VLayoutPiece &detail, std::atomic_bool &s data.followGrainline = d->followGrainline; data.positionsCache = d->positionsCache; data.isOriginPaperOrientationPortrait = d->originPaperOrientation; +#ifdef LAYOUT_DEBUG + data.details = d->details; + data.mutex = &mutex; +#endif const VBestSquare result = VPosition::ArrangeDetail(data, &stop, d->saveLength); +#ifdef LAYOUT_DEBUG + return SaveResult(result, detail, &mutex); +#else return SaveResult(result, detail); +#endif } //--------------------------------------------------------------------------------------------------------------------- @@ -259,7 +275,11 @@ int VLayoutPaper::Count() const } //--------------------------------------------------------------------------------------------------------------------- -bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail) +bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail +#ifdef LAYOUT_DEBUG + , QMutex *mutex +#endif + ) { if (bestResult.HasValidResult()) { @@ -287,6 +307,12 @@ bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece positionChache.boundingRect = VLayoutPiece::BoundingRect(layoutPoints); positionChache.layoutAllowancePath = VLayoutPiece::PainterPath(layoutPoints); d->positionsCache.append(positionChache); + +#ifdef LAYOUT_DEBUG +# ifdef SHOW_BEST + VPosition::DumpFrame(d->globalContour, workDetail, mutex, d->details); +# endif +#endif } else if (bestResult.IsTerminatedByException()) { diff --git a/src/libs/vlayout/vlayoutpaper.h b/src/libs/vlayout/vlayoutpaper.h index d913bcf1c..1e77ee890 100644 --- a/src/libs/vlayout/vlayoutpaper.h +++ b/src/libs/vlayout/vlayoutpaper.h @@ -44,6 +44,7 @@ class VLayoutPiece; class QGraphicsRectItem; class QRectF; class QGraphicsItem; +class QMutex; template class QList; template class QVector; @@ -107,7 +108,11 @@ public: private: QSharedDataPointer d; - bool SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail); + bool SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail +#ifdef LAYOUT_DEBUG + , QMutex *mutex +#endif + ); }; diff --git a/src/libs/vlayout/vposition.cpp b/src/libs/vlayout/vposition.cpp index b1cfd6f50..9947d3451 100644 --- a/src/libs/vlayout/vposition.cpp +++ b/src/libs/vlayout/vposition.cpp @@ -61,6 +61,85 @@ #include #endif +namespace +{ +#ifdef LAYOUT_DEBUG +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath ShowDirection(const QLineF &edge) +{ + const int arrowLength = 14; + QPainterPath path; + if (edge.length()/arrowLength < 5) + { + return path; + } + + QLineF arrow = edge; + arrow.setLength(edge.length()/2.0); + + //Reverse line because we want start arrow from this point + arrow = QLineF(arrow.p2(), arrow.p1()); + const qreal angle = arrow.angle();//we each time change line angle, better save original angle value + arrow.setLength(arrowLength);//arrow length in pixels + + arrow.setAngle(angle-35); + path.moveTo(arrow.p1()); + path.lineTo(arrow.p2()); + + arrow.setAngle(angle+35); + path.moveTo(arrow.p1()); + path.lineTo(arrow.p2()); + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath DumpContour(const QVector &points) +{ + QPainterPath path; + path.setFillRule(Qt::WindingFill); + if (points.count() >= 2) + { + for (qint32 i = 0; i < points.count()-1; ++i) + { + path.moveTo(points.at(i)); + path.lineTo(points.at(i+1)); + } + path.lineTo(points.at(0)); + +#ifdef SHOW_DIRECTION + for (qint32 i = 0; i < points.count()-1; ++i) + { + path.addPath(ShowDirection(QLineF(points.at(i), points.at(i+1)))); + } +#endif + +#ifdef SHOW_VERTICES + for (qint32 i = 0; i < points.count(); ++i) + { + path.addRect(points.at(i).x()-3, points.at(i).y()-3, 6, 6); + } +#endif + } + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath DumpDetails(const QVector &details) +{ + QPainterPath path; + path.setFillRule(Qt::WindingFill); + if (details.count() > 0) + { + for (auto &detail : details) + { + path.addPath(detail.ContourPath()); + } + } + return path; +} +#endif +} //anonymous namespace + //--------------------------------------------------------------------------------------------------------------------- VPosition::VPosition() {} @@ -246,6 +325,12 @@ bool VPosition::CheckCombineEdges(VLayoutPiece &detail, int j, int &dEdge) CombineEdges(detail, globalEdge, dEdge); +#ifdef LAYOUT_DEBUG +# ifdef SHOW_COMBINE + DumpFrame(m_data.gContour, detail, m_data.mutex, m_data.details); +# endif +#endif + CrossingType type = CrossingType::Intersection; if (not detail.IsForceFlipping() && SheetContains(detail.DetailBoundingRect())) { @@ -276,6 +361,12 @@ bool VPosition::CheckCombineEdges(VLayoutPiece &detail, int j, int &dEdge) if (flagMirror && not detail.IsForbidFlipping()) { +#ifdef LAYOUT_DEBUG +# ifdef SHOW_MIRROR + DumpFrame(m_data.gContour, detail, m_data.mutex, m_data.details); +# endif +#endif + dEdge = detail.LayoutEdgeByPoint(globalEdge.p2()); if (dEdge <= 0) @@ -319,6 +410,12 @@ bool VPosition::CheckRotationEdges(VLayoutPiece &detail, int j, int dEdge, qreal RotateEdges(detail, globalEdge, dEdge, angle); +#ifdef LAYOUT_DEBUG +# ifdef SHOW_ROTATION + DumpFrame(m_data.gContour, detail, m_data.mutex, m_data.details); +# endif +#endif + CrossingType type = CrossingType::Intersection; if (SheetContains(detail.DetailBoundingRect())) { @@ -349,6 +446,12 @@ void VPosition::RotateOnAngle(qreal angle) if (CheckRotationEdges(workDetail, m_data.j, m_data.i, angle)) { +#ifdef LAYOUT_DEBUG +# ifdef SHOW_CANDIDATE_BEST + DumpFrame(m_data.gContour, workDetail, m_data.mutex, m_data.details); +# endif +#endif + SaveCandidate(m_bestResult, workDetail, m_data.j, m_data.i, BestFrom::Rotation); } } @@ -497,6 +600,12 @@ void VPosition::FindBestPosition() int dEdge = m_data.i;// For mirror detail edge will be different if (CheckCombineEdges(workDetail, m_data.j, dEdge)) { +#ifdef LAYOUT_DEBUG +# ifdef SHOW_CANDIDATE_BEST + DumpFrame(m_data.gContour, workDetail, m_data.mutex, m_data.details); +# endif +#endif + SaveCandidate(m_bestResult, workDetail, m_data.j, dEdge, BestFrom::Combine); } @@ -515,3 +624,92 @@ void VPosition::FindBestPosition() FollowGrainline(); } } + +#ifdef LAYOUT_DEBUG +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::DumpFrame(const VContour &contour, const VLayoutPiece &detail, QMutex *mutex, + const QVector &details = QVector()) +{ + auto Bias = [](int length, int maxLength) + { + return length < maxLength && length*2 < maxLength ? length : maxLength-length; + }; + + const int biasWidth = Bias(contour.GetWidth(), QIMAGE_MAX); + const int biasHeight = Bias(contour.GetHeight(), QIMAGE_MAX); + + QPicture picture; + QPainter paint; + paint.begin(&picture); + + paint.setPen(QPen(Qt::black, 6, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + QPainterPath p; + if (contour.GetContour().isEmpty()) + { + p = DumpContour(contour.CutEmptySheetEdge()); + p.translate(biasWidth/2, biasHeight/2); + paint.drawPath(p); + } + else + { + p = DumpContour(contour.GetContour()); + p.translate(biasWidth/2, biasHeight/2); + paint.drawPath(p); + } + +#ifdef SHOW_CANDIDATE + paint.setPen(QPen(Qt::darkGreen, 6, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + p = DumpContour(detail.GetLayoutAllowancePoints()); + p.translate(biasWidth/2, biasHeight/2); + paint.drawPath(p); +#else + Q_UNUSED(detail) + Q_UNUSED(details) +#endif + +#ifdef ARRANGED_DETAILS + paint.setPen(QPen(Qt::blue, 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + p = DumpDetails(details); + p.translate(biasWidth/2, biasHeight/2); + paint.drawPath(p); +#else + Q_UNUSED(details) +#endif + + // Calculate bounding rect before draw sheet rect + const QRect pictureRect = picture.boundingRect(); + + // Sheet +#ifdef SHOW_SHEET + paint.setPen(QPen(Qt::darkRed, 15, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + paint.drawRect(QRectF(biasWidth/2, biasHeight/2, contour.GetWidth(), contour.GetHeight())); +#endif + + paint.end(); + + // Dump frame to image + // Note. If program was build with Address Sanitizer possible crashes. Address Sanitizer doesn't support big + // allocations. See page https://bitbucket.org/dismine/valentina/wiki/developers/Address_Sanitizer + QImage frameImage(pictureRect.width()+biasWidth, pictureRect.height()+biasHeight, QImage::Format_RGB32); + + if (frameImage.isNull()) + { + return; + } + + frameImage.fill(Qt::white); + + QPainter paintFrameImage; + paintFrameImage.begin(&frameImage); + paintFrameImage.drawPicture(0, 0, picture); + paintFrameImage.end(); + + QMutexLocker locker(mutex); + + static int frame = 0; + ++frame; + + const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug/%1.png").arg(frame); + frameImage.save (path); +} +#endif diff --git a/src/libs/vlayout/vposition.h b/src/libs/vlayout/vposition.h index b3db55370..2f80199e2 100644 --- a/src/libs/vlayout/vposition.h +++ b/src/libs/vlayout/vposition.h @@ -35,6 +35,10 @@ #include #include +#ifdef LAYOUT_DEBUG +#include +#endif + #include "vbestsquare.h" #include "vcontour.h" #include "vlayoutdef.h" @@ -51,6 +55,10 @@ struct VPositionData bool followGrainline{false}; QVector positionsCache{}; bool isOriginPaperOrientationPortrait{true}; +#ifdef LAYOUT_DEBUG + QVector details{}; + QMutex *mutex{nullptr}; +#endif }; QT_WARNING_PUSH @@ -72,6 +80,11 @@ public: static VBestSquare ArrangeDetail(const VPositionData &data, std::atomic_bool *stop, bool saveLength); +#ifdef LAYOUT_DEBUG + static void DumpFrame(const VContour &contour, const VLayoutPiece &detail, QMutex *mutex, + const QVector &details); +#endif + private: bool m_isValid{false}; VBestSquare m_bestResult{};