From 9210d31c2561aef492cdb2ba1cbfc4197b5a7486 Mon Sep 17 00:00:00 2001 From: dismine Date: Wed, 21 Jan 2015 23:49:38 +0200 Subject: [PATCH] First realization multithreading. --HG-- branch : feature --- src/libs/vlayout/vlayout.pri | 6 +- src/libs/vlayout/vlayoutdef.h | 4 +- src/libs/vlayout/vlayoutpaper.cpp | 578 ++----------------------- src/libs/vlayout/vlayoutpaper.h | 34 -- src/libs/vlayout/vposition.cpp | 691 ++++++++++++++++++++++++++++++ src/libs/vlayout/vposition.h | 123 ++++++ 6 files changed, 856 insertions(+), 580 deletions(-) create mode 100644 src/libs/vlayout/vposition.cpp create mode 100644 src/libs/vlayout/vposition.h diff --git a/src/libs/vlayout/vlayout.pri b/src/libs/vlayout/vlayout.pri index 116b75f0e..65bebdf49 100644 --- a/src/libs/vlayout/vlayout.pri +++ b/src/libs/vlayout/vlayout.pri @@ -14,7 +14,8 @@ HEADERS += \ $$PWD/vbank.h \ $$PWD/vcontour.h \ $$PWD/vcontour_p.h \ - $$PWD/vbestsquare.h + $$PWD/vbestsquare.h \ + $$PWD/vposition.h SOURCES += \ $$PWD/stable.cpp \ @@ -24,4 +25,5 @@ SOURCES += \ $$PWD/vlayoutpaper.cpp \ $$PWD/vbank.cpp \ $$PWD/vcontour.cpp \ - $$PWD/vbestsquare.cpp + $$PWD/vbestsquare.cpp \ + $$PWD/vposition.cpp diff --git a/src/libs/vlayout/vlayoutdef.h b/src/libs/vlayout/vlayoutdef.h index 2626258ea..5df8aa00d 100644 --- a/src/libs/vlayout/vlayoutdef.h +++ b/src/libs/vlayout/vlayoutdef.h @@ -46,7 +46,7 @@ enum class BestFrom : char Combine = 1 }; -#define LAYOUT_DEBUG // Enable debug mode +//#define LAYOUT_DEBUG // Enable debug mode #ifdef LAYOUT_DEBUG # define SHOW_VERTICES // Show contour vertices @@ -57,7 +57,7 @@ enum class BestFrom : char //# define SHOW_COMBINE //# define SHOW_MIRROR //# define SHOW_CANDIDATE_BEST -# define SHOW_BEST +//# define SHOW_BEST #endif//LAYOUT_DEBUG #endif // VLAYOUTDEF_H diff --git a/src/libs/vlayout/vlayoutpaper.cpp b/src/libs/vlayout/vlayoutpaper.cpp index 5498b0f88..4d1651ee5 100644 --- a/src/libs/vlayout/vlayoutpaper.cpp +++ b/src/libs/vlayout/vlayoutpaper.cpp @@ -29,6 +29,7 @@ #include "vlayoutpaper.h" #include "vlayoutpaper_p.h" #include "vbestsquare.h" +#include "vposition.h" #include #include @@ -38,6 +39,7 @@ #include #include #include +#include //--------------------------------------------------------------------------------------------------------------------- VLayoutPaper::VLayoutPaper() @@ -155,413 +157,52 @@ int VLayoutPaper::Count() const bool VLayoutPaper::AddToSheet(const VLayoutDetail &detail, bool &stop) { VBestSquare bestResult; + QThreadPool *thread_pool = QThreadPool::globalInstance(); + thread_pool->setMaxThreadCount(4); + QVector threads; for (int j=1; j <= d->globalContour.EdgesCount(); ++j) { for (int i=1; i<= detail.EdgesCount(); i++) { - QCoreApplication::processEvents(); + VPosition *thread = new VPosition(d->globalContour, j, detail, i); + //Info for debug + thread->setPaperIndex(d->paperIndex); + thread->setFrame(d->frame); + thread->setDetailsCount(d->details.count()); + thread->setDetails(d->details); - if (stop) - { - return false; - } + thread->setAutoDelete(false); + threads.append(thread); + thread_pool->start(thread); - // We should use copy of the detail. - VLayoutDetail workDetail = detail; - - int dEdge = i;// For mirror detail edge will be different - if (CheckCombineEdges(workDetail, j, dEdge)) - { - #ifdef LAYOUT_DEBUG - # ifdef SHOW_CANDIDATE_BEST - DrawDebug(d->globalContour, workDetail, d->frame+2, d->paperIndex, d->details.count(), - d->details); - # endif - #endif - - SaveCandidate(bestResult, workDetail, j, dEdge, BestFrom::Combine); - } - d->frame = d->frame + 3; - - for (int angle = 0; angle <= 360; angle = angle+20) - { - QCoreApplication::processEvents(); - - if (stop) - { - return false; - } - - // We should use copy of the detail. - VLayoutDetail workDetail = detail; - - if (CheckRotationEdges(workDetail, j, i, angle)) - { - #ifdef LAYOUT_DEBUG - # ifdef SHOW_CANDIDATE_BEST - ++d->frame; - DrawDebug(d->globalContour, workDetail, d->frame, d->paperIndex, d->details.count(), - d->details); - # endif - #endif - - SaveCandidate(bestResult, workDetail, j, i, BestFrom::Rotation); - } - ++d->frame; - } + d->frame = d->frame + 3 + 360/20*2; } } + if (thread_pool->waitForDone() == false) + { + return false; + } + + QCoreApplication::processEvents(); + + if (stop) + { + return false; + } + + for (int i=0; i < threads.size(); ++i) + { + bestResult.NewResult(threads.at(i)->getBestResult()); + } + + qDeleteAll(threads.begin(), threads.end()); + threads.clear(); + return SaveResult(bestResult, detail); } -//--------------------------------------------------------------------------------------------------------------------- -bool VLayoutPaper::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) const -{ - const QLineF globalEdge = d->globalContour.GlobalEdge(j); - bool flagMirror = false; - bool flagSquare = false; - - CombineEdges(detail, globalEdge, dEdge); - -#ifdef LAYOUT_DEBUG -# ifdef SHOW_COMBINE - DrawDebug(d->globalContour, detail, d->frame, d->paperIndex, d->details.count(), d->details); -# endif -#endif - - CrossingType type = CrossingType::Intersection; - if (SheetContains(detail.BoundingRect())) - { - type = Crossing(detail, j, dEdge); - } - - switch (type) - { - case CrossingType::EdgeError: - return false; - case CrossingType::Intersection: - detail.Mirror(globalEdge); - flagMirror = true; - break; - case CrossingType::NoIntersection: - { - switch (InsideContour(detail, dEdge)) - { - case InsideType::EdgeError: - return false; - case InsideType::Inside: - detail.Mirror(globalEdge); - flagMirror = true; - break; - case InsideType::Outside: - flagSquare = true; - break; - default: - break; - } - } - default: - break; - } - - if (flagMirror) - { - #ifdef LAYOUT_DEBUG - #ifdef SHOW_MIRROR - DrawDebug(d->globalContour, detail, d->frame+1, d->paperIndex, d->details.count(), d->details); - #endif - #endif - - dEdge = detail.EdgeByPoint(globalEdge.p2()); - if (dEdge <= 0) - { - return false; - } - - CrossingType type = CrossingType::Intersection; - if (SheetContains(detail.BoundingRect())) - { - type = Crossing(detail, j, dEdge); - } - - switch (type) - { - case CrossingType::EdgeError: - return false; - case CrossingType::Intersection: - flagSquare = false; - break; - case CrossingType::NoIntersection: - { - switch (InsideContour(detail, dEdge)) - { - case InsideType::EdgeError: - return false; - case InsideType::Inside: - flagSquare = false; - break; - case InsideType::Outside: - flagSquare = true; - break; - default: - break; - } - } - default: - break; - } - } - return flagSquare; -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VLayoutPaper::CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const -{ - const QLineF globalEdge = d->globalContour.GlobalEdge(j); - bool flagSquare = false; - - RotateEdges(detail, globalEdge, dEdge, angle); - -#ifdef LAYOUT_DEBUG - #ifdef SHOW_ROTATION - DrawDebug(d->globalContour, detail, d->frame, d->paperIndex, d->details.count(), d->details); - #endif -#endif - - CrossingType type = CrossingType::Intersection; - if (SheetContains(detail.BoundingRect())) - { - type = Crossing(detail, j, dEdge); - } - - switch (type) - { - case CrossingType::EdgeError: - return false; - case CrossingType::Intersection: - flagSquare = false; - break; - case CrossingType::NoIntersection: - { - switch (InsideContour(detail, dEdge)) - { - case InsideType::EdgeError: - return false; - case InsideType::Inside: - flagSquare = false; - break; - case InsideType::Outside: - flagSquare = true; - break; - default: - break; - } - } - default: - break; - } - return flagSquare; -} - -//--------------------------------------------------------------------------------------------------------------------- -VLayoutPaper::CrossingType VLayoutPaper::Crossing(const VLayoutDetail &detail, const int &globalI, - const int &detailI) const -{ - int globalEdgesCount = d->globalContour.EdgesCount(); - if (globalEdgesCount == 0) - { - globalEdgesCount = 1;// For blank sheet - } - - const int detailEdgesCount = detail.EdgesCount(); - if (detailEdgesCount < 3) - { - return CrossingType::EdgeError; - } - - for(int i = 1; i <= globalEdgesCount; i++) - { - const QLineF globalEdge = d->globalContour.GlobalEdge(i); - if (globalEdge.isNull()) // Got null edge - { - return CrossingType::EdgeError; - } - - for(int j = 1; j <= detailEdgesCount; j++) - { - if (i == globalI && j == detailI) - { - continue; - } - - const QLineF detailEdge = detail.Edge(j); - if (detailEdge.isNull()) // Got null edge - { - return CrossingType::EdgeError; - } - - QPointF xPoint; - QLineF::IntersectType type = globalEdge.intersect(detailEdge, &xPoint); - - if (type == QLineF::BoundedIntersection) - { - if (TrueIntersection(d->globalContour.GlobalEdge(globalI), detail.Edge(detailI), xPoint)) - { - return CrossingType::Intersection; - } - } - } - } - - return CrossingType::NoIntersection; -} - -//--------------------------------------------------------------------------------------------------------------------- -VLayoutPaper::InsideType VLayoutPaper::InsideContour(const VLayoutDetail &detail, const int &detailI) const -{ - if (detail.EdgesCount() < 3) - { - return InsideType::EdgeError; - } - - const QVector lPoints = detail.GetLayoutAllowencePoints(); - - const QLineF detailEdge = detail.Edge(detailI); - if (detailEdge.isNull()) // Got null edge - { - return InsideType::EdgeError; - } - - if (d->details.isEmpty()) - { - const QLineF globalEdge = d->globalContour.GlobalEdge(1); - for(int i = 0; i < lPoints.count(); i++) - { - if (CheckSide(globalEdge, lPoints.at(i)) < 0) - { - return InsideType::Inside; - } - } - } - else - { - const int polyCorners = d->globalContour.EdgesCount(); - int j = polyCorners-1; - - QVector constant; - QVector multiple; - - for(int i=0; iglobalContour.at(i).x(); - const qreal xj = d->globalContour.at(j).x(); - const qreal yi = d->globalContour.at(i).y(); - const qreal yj = d->globalContour.at(j).y(); - if(qFuzzyCompare(yj, yi)) - { - constant.insert(i, xi); - multiple.insert(i, 0); - } - else - { - constant.insert(i, xi - (yi*xj)/(yj-yi) + (yi*xi)/(yj-yi)); - multiple.insert(i, (xj-xi)/(yj-yi)); - } - - j=i; - } - - for(int m = 1; m <= detail.EdgesCount(); ++m) - { - if (m == detailI) - { - continue; - } - - const QLineF detailEdge = detail.Edge(m); - if (detailEdge.isNull()) // Got null edge - { - return InsideType::EdgeError; - } - - const QVector p = Triplet(detailEdge); - for (int n=0; nglobalContour.at(i).y(); - const qreal yj = d->globalContour.at(j).y(); - - if (((yi < p.at(n).y() && yj >= p.at(n).y()) || (yj < p.at(n).y() && yi >= p.at(n).y()))) - { - oddNodes ^= (p.at(n).y() * multiple.at(i) + constant.at(i) < p.at(n).x()); - } - - j=i; - } - - if (oddNodes) - { - return InsideType::Inside; - } - } - } - } - return InsideType::Outside; -} - -//--------------------------------------------------------------------------------------------------------------------- -qreal VLayoutPaper::CheckSide(const QLineF &edge, const QPointF &p) const -{ - return (edge.x2() - edge.x1()) * (p.y() - edge.y1()) - (edge.y2() - edge.y1()) * (p.x() - edge.x1()); -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VLayoutPaper::SheetContains(const QRectF &rect) const -{ - const QRectF bRect(0, 0, d->globalContour.GetWidth(), d->globalContour.GetHeight()); - return bRect.contains(rect); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPaper::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const -{ - QLineF detailEdge = detail.Edge(dEdge); - - // Find distance between two edges for two begin vertex. - const qreal dx = globalEdge.x2() - detailEdge.x2(); - const qreal dy = globalEdge.y2() - detailEdge.y2(); - - detailEdge.translate(dx, dy); // Use values for translate detail edge. - - const qreal angle_between = globalEdge.angleTo(detailEdge); // Seek angle between two edges. - - // Now we move detail to position near to global contour edge. - detail.Translate(dx, dy); - detail.Rotate(detailEdge.p2(), -angle_between); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPaper::RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const -{ - QLineF detailEdge = detail.Edge(dEdge); - - // Find distance between two edges for two begin vertex. - const qreal dx = globalEdge.x2() - detailEdge.x2(); - const qreal dy = globalEdge.y2() - detailEdge.y2(); - - detailEdge.translate(dx, dy); // Use values for translate detail edge. - - // Now we move detail to position near to global contour edge. - detail.Translate(dx, dy); - detail.Rotate(globalEdge.p2(), angle); -} - //--------------------------------------------------------------------------------------------------------------------- bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutDetail &detail) { @@ -582,7 +223,7 @@ bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutDetail #ifdef LAYOUT_DEBUG # ifdef SHOW_BEST - DrawDebug(d->globalContour, workDetail, UINT_MAX, d->paperIndex, d->details.count(), d->details); + VPosition::DrawDebug(d->globalContour, workDetail, UINT_MAX, d->paperIndex, d->details.count(), d->details); # endif #endif } @@ -601,153 +242,6 @@ void VLayoutPaper::SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &d detail.GetMatrix(), detail.IsMirror(), type); } -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPaper::DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex, - int detailsCount, const QVector &details) -{ - QImage frameImage(contour.GetWidth()*2, contour.GetHeight()*2, QImage::Format_RGB32); - frameImage.fill(Qt::white); - QPainter paint; - paint.begin(&frameImage); - - paint.setPen(QPen(Qt::darkRed, 10, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); - paint.drawRect(QRectF(contour.GetWidth()/2, contour.GetHeight()/2, contour.GetWidth(), contour.GetHeight())); - - paint.setPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); - QPainterPath p; - if (contour.GetContour().isEmpty()) - { - p = DrawContour(contour.CutEdge(QLineF(0, 0, contour.GetWidth(), 0))); - p.translate(contour.GetWidth()/2, contour.GetHeight()/2); - paint.drawPath(p); - } - else - { - p = DrawContour(contour.GetContour()); - p.translate(contour.GetWidth()/2, contour.GetHeight()/2); - paint.drawPath(p); - } - -#ifdef SHOW_CANDIDATE - paint.setPen(QPen(Qt::darkGreen, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); - p = DrawContour(detail.GetLayoutAllowencePoints()); - p.translate(contour.GetWidth()/2, contour.GetHeight()/2); - paint.drawPath(p); -#endif - -#ifdef ARRANGED_DETAILS - paint.setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); - p = DrawDetails(details); - p.translate(contour.GetWidth()/2, contour.GetHeight()/2); - paint.drawPath(p); -#else - Q_UNUSED(detail) -#endif - - paint.end(); - const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug/")+QString("%1_%2_%3.png").arg(paperIndex) - .arg(detailsCount).arg(frame); - frameImage.save (path); -} - -//--------------------------------------------------------------------------------------------------------------------- -QPainterPath VLayoutPaper::ShowDirection(const QLineF &edge) -{ - 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(14);//arrow length in pixels - - QPainterPath path; - 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 VLayoutPaper::DrawContour(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 VLayoutPaper::DrawDetails(const QVector &details) -{ - QPainterPath path; - path.setFillRule(Qt::WindingFill); - if (details.count() > 0) - { - for (int i = 0; i < details.size(); ++i) - { - path.addPath(details.at(i).ContourPath()); - } - } - return path; -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VLayoutPaper::TrueIntersection(const QLineF &gEdge, const QLineF &dEdge, const QPointF &p) const -{ - const QPointF pX = RoundedPoint(p); - const QPointF gP1 = RoundedPoint(gEdge.p1()); - const QPointF gP2 = RoundedPoint(gEdge.p2()); - const QPointF dP1 = RoundedPoint(dEdge.p1()); - const QPointF dP2 = RoundedPoint(dEdge.p2()); - return !(pX == gP1 || pX == gP2 || pX == dP1 || pX == dP2); -} - -//--------------------------------------------------------------------------------------------------------------------- -QPointF VLayoutPaper::RoundedPoint(const QPointF &p) const -{ - return QPointF(qRound(p.x()), qRound(p.y())); -} - -//--------------------------------------------------------------------------------------------------------------------- -QVector VLayoutPaper::Triplet(const QLineF &edge) const -{ - QVector p; - QLineF line = edge; - line.setLength(edge.length()/2); - - p.append(edge.p1()); - p.append(line.p2()); - p.append(edge.p2()); - return p; -} - //--------------------------------------------------------------------------------------------------------------------- QGraphicsItem *VLayoutPaper::GetItem() const { diff --git a/src/libs/vlayout/vlayoutpaper.h b/src/libs/vlayout/vlayoutpaper.h index 496f6a0bb..2bc3c45f6 100644 --- a/src/libs/vlayout/vlayoutpaper.h +++ b/src/libs/vlayout/vlayoutpaper.h @@ -73,45 +73,11 @@ public: private: QSharedDataPointer d; - enum class CrossingType : char - { - NoIntersection = 0, - Intersection = 1, - EdgeError = 2 - }; - - enum class InsideType : char - { - Outside = 0, - Inside = 1, - EdgeError = 2 - }; - bool AddToSheet(const VLayoutDetail &detail, bool &stop); - bool CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) const; - bool CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const; - - CrossingType Crossing(const VLayoutDetail &detail, const int &globalI, const int &detailI) const; - InsideType InsideContour(const VLayoutDetail &detail, const int &detailI) const; - qreal CheckSide(const QLineF &edge, const QPointF &p) const; - bool SheetContains(const QRectF &rect) const; - - void CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const; - void RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const; - bool SaveResult(const VBestSquare &bestResult, const VLayoutDetail &detail); void SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &detail, int globalI, int detJ, BestFrom type); - static void DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex, - int detailsCount, const QVector &details = QVector()); - static QPainterPath ShowDirection(const QLineF &edge); - static QPainterPath DrawContour(const QVector &points); - static QPainterPath DrawDetails(const QVector &details); - - bool TrueIntersection(const QLineF &gEdge, const QLineF &dEdge, const QPointF &p) const; - QPointF RoundedPoint(const QPointF &p) const; - QVector Triplet(const QLineF &edge) const; }; #endif // VLAYOUTPAPER_H diff --git a/src/libs/vlayout/vposition.cpp b/src/libs/vlayout/vposition.cpp new file mode 100644 index 000000000..8e0f309ec --- /dev/null +++ b/src/libs/vlayout/vposition.cpp @@ -0,0 +1,691 @@ +/************************************************************************ + ** + ** @file vposition.cpp + ** @author Roman Telezhynskyi + ** @date 20 1, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vposition.h" + +#include +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +VPosition::VPosition(const VContour &gContour, int j, const VLayoutDetail &detail, int i) + :QRunnable(), bestResult(VBestSquare()), gContour(gContour), detail(detail), i(i), j(j), paperIndex(0), frame(0), + detailsCount(0), details(QVector()) +{} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::run() +{ + // We should use copy of the detail. + VLayoutDetail workDetail = detail; + + int dEdge = i;// For mirror detail edge will be different + if (CheckCombineEdges(workDetail, j, dEdge)) + { + #ifdef LAYOUT_DEBUG + # ifdef SHOW_CANDIDATE_BEST + DrawDebug(gContour, workDetail, frame+2, paperIndex, detailsCount, details); + # endif + #endif + + SaveCandidate(bestResult, workDetail, j, dEdge, BestFrom::Combine); + } + frame = frame + 3; + + for (int angle = 0; angle <= 360; angle = angle+20) + { + // We should use copy of the detail. + VLayoutDetail workDetail = detail; + + if (CheckRotationEdges(workDetail, j, i, angle)) + { + #ifdef LAYOUT_DEBUG + # ifdef SHOW_CANDIDATE_BEST + ++frame; + DrawDebug(gContour, workDetail, frame, paperIndex, detailsCount, details); + # endif + #endif + + SaveCandidate(bestResult, workDetail, j, i, BestFrom::Rotation); + } + ++frame; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +quint32 VPosition::getPaperIndex() const +{ + return paperIndex; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::setPaperIndex(const quint32 &value) +{ + paperIndex = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +quint32 VPosition::getFrame() const +{ + return frame; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::setFrame(const quint32 &value) +{ + frame = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +quint32 VPosition::getDetailsCount() const +{ + return detailsCount; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::setDetailsCount(const quint32 &value) +{ + detailsCount = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::setDetails(const QVector &details) +{ + this->details = details; +} + +//--------------------------------------------------------------------------------------------------------------------- +VBestSquare VPosition::getBestResult() const +{ + return bestResult; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex, + int detailsCount, const QVector &details) +{ + QImage frameImage(contour.GetWidth()*2, contour.GetHeight()*2, QImage::Format_RGB32); + frameImage.fill(Qt::white); + QPainter paint; + paint.begin(&frameImage); + + paint.setPen(QPen(Qt::darkRed, 10, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + paint.drawRect(QRectF(contour.GetWidth()/2, contour.GetHeight()/2, contour.GetWidth(), contour.GetHeight())); + + paint.setPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + QPainterPath p; + if (contour.GetContour().isEmpty()) + { + p = DrawContour(contour.CutEdge(QLineF(0, 0, contour.GetWidth(), 0))); + p.translate(contour.GetWidth()/2, contour.GetHeight()/2); + paint.drawPath(p); + } + else + { + p = DrawContour(contour.GetContour()); + p.translate(contour.GetWidth()/2, contour.GetHeight()/2); + paint.drawPath(p); + } + +#ifdef SHOW_CANDIDATE + paint.setPen(QPen(Qt::darkGreen, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + p = DrawContour(detail.GetLayoutAllowencePoints()); + p.translate(contour.GetWidth()/2, contour.GetHeight()/2); + paint.drawPath(p); +#endif + +#ifdef ARRANGED_DETAILS + paint.setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); + p = DrawDetails(details); + p.translate(contour.GetWidth()/2, contour.GetHeight()/2); + paint.drawPath(p); +#endif + + paint.end(); + const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug/")+QString("%1_%2_%3.png").arg(paperIndex) + .arg(detailsCount).arg(frame); + frameImage.save (path); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &detail, int globalI, int detJ, + BestFrom type) +{ + QVector newGContour = gContour.UniteWithContour(detail, globalI, detJ, type); + newGContour.append(newGContour.first()); + const QRectF rec = QPolygonF(newGContour).boundingRect(); + bestResult.NewResult(static_cast(rec.width()*rec.height()), globalI, detJ, detail.GetMatrix(), + detail.IsMirror(), type); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPosition::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) const +{ + const QLineF globalEdge = gContour.GlobalEdge(j); + bool flagMirror = false; + bool flagSquare = false; + + CombineEdges(detail, globalEdge, dEdge); + +#ifdef LAYOUT_DEBUG +# ifdef SHOW_COMBINE + DrawDebug(gContour, detail, frame, paperIndex, detailsCount, details); +# endif +#endif + + CrossingType type = CrossingType::Intersection; + if (SheetContains(detail.BoundingRect())) + { + type = Crossing(detail, j, dEdge); + } + + switch (type) + { + case CrossingType::EdgeError: + return false; + case CrossingType::Intersection: + detail.Mirror(globalEdge); + flagMirror = true; + break; + case CrossingType::NoIntersection: + { + switch (InsideContour(detail, dEdge)) + { + case InsideType::EdgeError: + return false; + case InsideType::Inside: + detail.Mirror(globalEdge); + flagMirror = true; + break; + case InsideType::Outside: + flagSquare = true; + break; + default: + break; + } + } + default: + break; + } + + if (flagMirror) + { + #ifdef LAYOUT_DEBUG + #ifdef SHOW_MIRROR + DrawDebug(gContour, detail, frame+1, paperIndex, detailsCount, details); + #endif + #endif + + dEdge = detail.EdgeByPoint(globalEdge.p2()); + if (dEdge <= 0) + { + return false; + } + + CrossingType type = CrossingType::Intersection; + if (SheetContains(detail.BoundingRect())) + { + type = Crossing(detail, j, dEdge); + } + + switch (type) + { + case CrossingType::EdgeError: + return false; + case CrossingType::Intersection: + flagSquare = false; + break; + case CrossingType::NoIntersection: + { + switch (InsideContour(detail, dEdge)) + { + case InsideType::EdgeError: + return false; + case InsideType::Inside: + flagSquare = false; + break; + case InsideType::Outside: + flagSquare = true; + break; + default: + break; + } + } + default: + break; + } + } + return flagSquare; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPosition::CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const +{ + const QLineF globalEdge = gContour.GlobalEdge(j); + bool flagSquare = false; + + RotateEdges(detail, globalEdge, dEdge, angle); + +#ifdef LAYOUT_DEBUG + #ifdef SHOW_ROTATION + DrawDebug(gContour, detail, frame, paperIndex, detailsCount, details); + #endif +#endif + + CrossingType type = CrossingType::Intersection; + if (SheetContains(detail.BoundingRect())) + { + type = Crossing(detail, j, dEdge); + } + + switch (type) + { + case CrossingType::EdgeError: + return false; + case CrossingType::Intersection: + flagSquare = false; + break; + case CrossingType::NoIntersection: + { + switch (InsideContour(detail, dEdge)) + { + case InsideType::EdgeError: + return false; + case InsideType::Inside: + flagSquare = false; + break; + case InsideType::Outside: + flagSquare = true; + break; + default: + break; + } + } + default: + break; + } + return flagSquare; +} + +//--------------------------------------------------------------------------------------------------------------------- +VPosition::CrossingType VPosition::Crossing(const VLayoutDetail &detail, const int &globalI, const int &detailI) const +{ + int globalEdgesCount = gContour.EdgesCount(); + if (globalEdgesCount == 0) + { + globalEdgesCount = 1;// For blank sheet + } + + const int detailEdgesCount = detail.EdgesCount(); + if (detailEdgesCount < 3) + { + return CrossingType::EdgeError; + } + + for(int i = 1; i <= globalEdgesCount; i++) + { + const QLineF globalEdge = gContour.GlobalEdge(i); + if (globalEdge.isNull()) // Got null edge + { + return CrossingType::EdgeError; + } + + for(int j = 1; j <= detailEdgesCount; j++) + { + if (i == globalI && j == detailI) + { + continue; + } + + const QLineF detailEdge = detail.Edge(j); + if (detailEdge.isNull()) // Got null edge + { + return CrossingType::EdgeError; + } + + QPointF xPoint; + QLineF::IntersectType type = globalEdge.intersect(detailEdge, &xPoint); + + if (type == QLineF::BoundedIntersection) + { + if (TrueIntersection(gContour.GlobalEdge(globalI), detail.Edge(detailI), xPoint)) + { + return CrossingType::Intersection; + } + } + } + } + + return CrossingType::NoIntersection; +} + +//--------------------------------------------------------------------------------------------------------------------- +VPosition::InsideType VPosition::InsideContour(const VLayoutDetail &detail, const int &detailI) const +{ + if (detail.EdgesCount() < 3) + { + return InsideType::EdgeError; + } + + const QVector lPoints = detail.GetLayoutAllowencePoints(); + + const QLineF detailEdge = detail.Edge(detailI); + if (detailEdge.isNull()) // Got null edge + { + return InsideType::EdgeError; + } + + if (details.isEmpty()) + { + const QLineF globalEdge = gContour.GlobalEdge(1); + for(int i = 0; i < lPoints.count(); i++) + { + if (CheckSide(globalEdge, lPoints.at(i)) < 0) + { + return InsideType::Inside; + } + } + } + else + { + const int polyCorners = gContour.EdgesCount(); + int j = polyCorners-1; + + QVector constant; + QVector multiple; + + for(int i=0; i p = Triplet(detailEdge); + for (int n=0; n= p.at(n).y()) || (yj < p.at(n).y() && yi >= p.at(n).y()))) + { + oddNodes ^= (p.at(n).y() * multiple.at(i) + constant.at(i) < p.at(n).x()); + } + + j=i; + } + + if (oddNodes) + { + return InsideType::Inside; + } + } + } + } + return InsideType::Outside; +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPosition::CheckSide(const QLineF &edge, const QPointF &p) const +{ + return (edge.x2() - edge.x1()) * (p.y() - edge.y1()) - (edge.y2() - edge.y1()) * (p.x() - edge.x1()); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPosition::SheetContains(const QRectF &rect) const +{ + const QRectF bRect(0, 0, gContour.GetWidth(), gContour.GetHeight()); + return bRect.contains(rect); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const +{ + QLineF detailEdge = detail.Edge(dEdge); + + // Find distance between two edges for two begin vertex. + const qreal dx = globalEdge.x2() - detailEdge.x2(); + const qreal dy = globalEdge.y2() - detailEdge.y2(); + + detailEdge.translate(dx, dy); // Use values for translate detail edge. + + const qreal angle_between = globalEdge.angleTo(detailEdge); // Seek angle between two edges. + + // Now we move detail to position near to global contour edge. + detail.Translate(dx, dy); + detail.Rotate(detailEdge.p2(), -angle_between); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const +{ + QLineF detailEdge = detail.Edge(dEdge); + + // Find distance between two edges for two begin vertex. + const qreal dx = globalEdge.x2() - detailEdge.x2(); + const qreal dy = globalEdge.y2() - detailEdge.y2(); + + detailEdge.translate(dx, dy); // Use values for translate detail edge. + + // Now we move detail to position near to global contour edge. + detail.Translate(dx, dy); + detail.Rotate(globalEdge.p2(), angle); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPosition::AppendWhole(QVector &contour, const VLayoutDetail &detail, int detJ, unsigned int shift) +{ + int processedEdges = 0; + const int nD = detail.EdgesCount(); + int j = detJ+1; + do + { + if (j > nD) + { + j=1; + } + const QVector points = CutEdge(detail.Edge(j), shift); + for (int i = 0; i < points.size()-1; ++i) + { + contour.append(points.at(i)); + } + ++processedEdges; + ++j; + }while (processedEdges < nD); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPolygonF VPosition::GlobalPolygon() const +{ + QVector points = gContour.GetContour(); + points.append(points.first()); + return QPolygonF(points); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPosition::CutEdge(const QLineF &edge, unsigned int shift) +{ + QVector points; + if (shift == 0) + { + points.append(edge.p1()); + points.append(edge.p2()); + } + + const int n = qFloor(edge.length()/shift); + + if (n <= 0) + { + points.append(edge.p1()); + points.append(edge.p2()); + } + else + { + const qreal nShift = edge.length()/n; + for (int i = 1; i <= n+1; ++i) + { + QLineF l1 = edge; + l1.setLength(nShift*(i-1)); + points.append(l1.p2()); + } + } + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPosition::TrueIntersection(const QLineF &gEdge, const QLineF &dEdge, const QPointF &p) const +{ + const QPointF pX = RoundedPoint(p); + const QPointF gP1 = RoundedPoint(gEdge.p1()); + const QPointF gP2 = RoundedPoint(gEdge.p2()); + const QPointF dP1 = RoundedPoint(dEdge.p1()); + const QPointF dP2 = RoundedPoint(dEdge.p2()); + return !(pX == gP1 || pX == gP2 || pX == dP1 || pX == dP2); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPosition::RoundedPoint(const QPointF &p) const +{ + return QPointF(qRound(p.x()), qRound(p.y())); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPosition::Triplet(const QLineF &edge) const +{ + QVector p; + QLineF line = edge; + line.setLength(edge.length()/2); + + p.append(edge.p1()); + p.append(line.p2()); + p.append(edge.p2()); + return p; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPosition::ShowDirection(const QLineF &edge) +{ + 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(14);//arrow length in pixels + + QPainterPath path; + 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 VPosition::DrawContour(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 VPosition::DrawDetails(const QVector &details) +{ + QPainterPath path; + path.setFillRule(Qt::WindingFill); + if (details.count() > 0) + { + for (int i = 0; i < details.size(); ++i) + { + path.addPath(details.at(i).ContourPath()); + } + } + return path; +} diff --git a/src/libs/vlayout/vposition.h b/src/libs/vlayout/vposition.h new file mode 100644 index 000000000..d8b2edbe4 --- /dev/null +++ b/src/libs/vlayout/vposition.h @@ -0,0 +1,123 @@ +/************************************************************************ + ** + ** @file vposition.h + ** @author Roman Telezhynskyi + ** @date 20 1, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPOSITION_H +#define VPOSITION_H + +#include +#include + +#include "vlayoutdef.h" +#include "vbestsquare.h" +#include "vcontour.h" +#include "vlayoutdetail.h" + +class QPointF; +class QRectF; +class QLineF; +class QPolygonF; +class QPainterPath; + +class VPosition : public QRunnable +{ +public: + VPosition(const VContour &gContour, int j, const VLayoutDetail &detail, int i); + virtual ~VPosition(){} + + virtual void run(); + + quint32 getPaperIndex() const; + void setPaperIndex(const quint32 &value); + + quint32 getFrame() const; + void setFrame(const quint32 &value); + + quint32 getDetailsCount() const; + void setDetailsCount(const quint32 &value); + + void setDetails(const QVector &details); + + VBestSquare getBestResult() const; + + static void DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex, + int detailsCount, const QVector &details = QVector()); + +private: + Q_DISABLE_COPY(VPosition) + VBestSquare bestResult; + const VContour gContour; + const VLayoutDetail detail; + int i; + int j; + quint32 paperIndex; + quint32 frame; + quint32 detailsCount; + QVector details; + + enum class CrossingType : char + { + NoIntersection = 0, + Intersection = 1, + EdgeError = 2 + }; + + enum class InsideType : char + { + Outside = 0, + Inside = 1, + EdgeError = 2 + }; + + void SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &detail, int globalI, int detJ, BestFrom type); + + bool CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) const; + bool CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const; + + CrossingType Crossing(const VLayoutDetail &detail, const int &globalI, const int &detailI) const; + InsideType InsideContour(const VLayoutDetail &detail, const int &detailI) const; + qreal CheckSide(const QLineF &edge, const QPointF &p) const; + bool SheetContains(const QRectF &rect) const; + + void CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const; + void RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const; + + QPolygonF GlobalPolygon() const; + + bool TrueIntersection(const QLineF &gEdge, const QLineF &dEdge, const QPointF &p) const; + QPointF RoundedPoint(const QPointF &p) const; + QVector Triplet(const QLineF &edge) const; + + static QPainterPath ShowDirection(const QLineF &edge); + static QPainterPath DrawContour(const QVector &points); + static QPainterPath DrawDetails(const QVector &details); + + static void AppendWhole(QVector &contour, const VLayoutDetail &detail, int detJ, unsigned int shift); + static QVector CutEdge(const QLineF &edge, unsigned int shift); +}; + +#endif // VPOSITION_H