/************************************************************************ ** ** @file vbank.cpp ** @author Roman Telezhynskyi ** @date 11 1, 2015 ** ** @brief ** @copyright ** This source code is part of the Valentina project, a pattern making ** program, whose allow create and modeling patterns of clothing. ** Copyright (C) 2013-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 "vbank.h" #include #include "../vmisc/diagnostic.h" #include "../vmisc/vabstractapplication.h" #include "vlayoutpiece.h" QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes") QT_WARNING_DISABLE_INTEL(1418) Q_LOGGING_CATEGORY(lBank, "layout.bank") QT_WARNING_POP // An annoying char define, from the Windows team in // #define small char // http://stuartjames.info/Journal/c--visual-studio-2012-vs2012--win8--converting-projects-up-some-conflicts-i-found.aspx #if defined (Q_OS_WIN) && defined (Q_CC_MSVC) #pragma push_macro("small") #undef small #endif namespace { QVector PrepareQuantity(const QVector &details) { QVector withQuantity; withQuantity.reserve(details.size()); for(auto &piece : details) { for (int i = 0; i < piece.GetQuantity(); ++i) { withQuantity.append(piece); } } return withQuantity; } } //--------------------------------------------------------------------------------------------------------------------- VBank::VBank() : details(), unsorted(), big(), middle(), small(), layoutWidth(0), caseType(Cases::CaseDesc), prepare(false), diagonal(0) {} //--------------------------------------------------------------------------------------------------------------------- qreal VBank::GetLayoutWidth() const { return layoutWidth; } //--------------------------------------------------------------------------------------------------------------------- void VBank::SetLayoutWidth(qreal value) { layoutWidth = value; Reset(); } //--------------------------------------------------------------------------------------------------------------------- bool VBank::IsNestQuantity() const { return m_nestQuantity; } //--------------------------------------------------------------------------------------------------------------------- void VBank::SetNestQuantity(bool value) { m_nestQuantity = value; } //--------------------------------------------------------------------------------------------------------------------- void VBank::SetDetails(const QVector &details) { this->details = details; Reset(); } //--------------------------------------------------------------------------------------------------------------------- int VBank::GetNext() { if (prepare == false) { return -1; } if (LeftToArrange() == 0) { if (unsorted.isEmpty()) { return -1; } else { PrepareGroup(); } } switch (caseType) { case Cases::CaseThreeGroup: return GetNextThreeGroups(); case Cases::CaseTwoGroup: return GetNextTwoGroups(); case Cases::CaseDesc: return GetNextDescGroup(); default: return -1; } } //--------------------------------------------------------------------------------------------------------------------- VLayoutPiece VBank::GetDetail(int i) const { if (i >= 0 && i < details.size()) { return details.at(i); } else { return VLayoutPiece(); } } //--------------------------------------------------------------------------------------------------------------------- void VBank::Arranged(int i) { if (big.contains(i)) { big.remove(i); return; } if (middle.contains(i)) { middle.remove(i); return; } if (small.contains(i)) { small.remove(i); } } //--------------------------------------------------------------------------------------------------------------------- void VBank::NotArranged(int i) { if (big.contains(i)) { unsorted.insert(i, big.value(i)); big.remove(i); return; } if (middle.contains(i)) { unsorted.insert(i, middle.value(i)); middle.remove(i); return; } if (small.contains(i)) { unsorted.insert(i, small.value(i)); small.remove(i); } } //--------------------------------------------------------------------------------------------------------------------- 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) { qCCritical(lBank, "Preparing data for layout error: Layout paper sheet <= 0"); prepare = false; return prepare; } if (details.isEmpty()) { qCCritical(lBank, "Preparing data for layout error: List of details is empty"); prepare = false; return prepare; } if (m_nestQuantity) { details = PrepareQuantity(details); } 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" " to check how seam allowance behave.").arg(details.at(i).GetName()); qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; } const qreal d = details.at(i).Diagonal(); if (d > diagonal) { diagonal = d; } } prepare = true; return prepare; } //--------------------------------------------------------------------------------------------------------------------- void VBank::Reset() { prepare = false; unsorted.clear(); big.clear(); middle.clear(); small.clear(); diagonal = 0; } //--------------------------------------------------------------------------------------------------------------------- void VBank::SetCaseType(Cases caseType) { this->caseType = caseType; } //--------------------------------------------------------------------------------------------------------------------- int VBank::AllDetailsCount() const { return unsorted.count() + big.count() + middle.count() + small.count(); } //--------------------------------------------------------------------------------------------------------------------- int VBank::LeftToArrange() const { return big.count() + middle.count() + small.count(); } //--------------------------------------------------------------------------------------------------------------------- qreal VBank::GetBiggestDiagonal() const { return diagonal; } //--------------------------------------------------------------------------------------------------------------------- int VBank::ArrangedCount() const { return details.size() - AllDetailsCount(); } //--------------------------------------------------------------------------------------------------------------------- void VBank::PrepareGroup() { switch (caseType) { case Cases::CaseThreeGroup: PrepareThreeGroups(); break; case Cases::CaseTwoGroup: PrepareTwoGroups(); break; case Cases::CaseDesc: PrepareDescGroup(); break; default: break; } } //--------------------------------------------------------------------------------------------------------------------- void VBank::PrepareThreeGroups() { qint64 sMax = LLONG_MIN; qint64 sMin = LLONG_MAX; SqMaxMin(sMax, sMin); const qint64 s1 = sMax - (sMax - sMin)/3; const qint64 s2 = sMin + (sMax - sMin)/3; QHash::const_iterator i = unsorted.constBegin(); while (i != unsorted.constEnd()) { if (i.value() > s1) { big.insert(i.key(), i.value()); } else if (s1 >= i.value() && i.value() > s2) { middle.insert(i.key(), i.value()); } else { small.insert(i.key(), i.value()); } ++i; } unsorted.clear(); } //--------------------------------------------------------------------------------------------------------------------- void VBank::PrepareTwoGroups() { qint64 sMax = LLONG_MIN; qint64 sMin = LLONG_MAX; SqMaxMin(sMax, sMin); const qint64 s = (sMax + sMin)/2; QHash::const_iterator i = unsorted.constBegin(); while (i != unsorted.constEnd()) { if (i.value() >= s) { big.insert(i.key(), i.value()); } else { small.insert(i.key(), i.value()); } ++i; } unsorted.clear(); } //--------------------------------------------------------------------------------------------------------------------- void VBank::PrepareDescGroup() { big = unsorted; unsorted.clear(); } //--------------------------------------------------------------------------------------------------------------------- int VBank::GetNextThreeGroups() const { if (big.isEmpty() == false) { QHash::const_iterator i = big.constBegin(); return i.key(); } if (middle.isEmpty() == false) { QHash::const_iterator i = middle.constBegin(); return i.key(); } if (small.isEmpty() == false) { QHash::const_iterator i = small.constBegin(); return i.key(); } return -1; } //--------------------------------------------------------------------------------------------------------------------- int VBank::GetNextTwoGroups() const { if (big.isEmpty() == false) { QHash::const_iterator i = big.constBegin(); return i.key(); } if (small.isEmpty() == false) { QHash::const_iterator i = small.constBegin(); return i.key(); } return -1; } //--------------------------------------------------------------------------------------------------------------------- int VBank::GetNextDescGroup() const { int index = -1; qint64 sMax = LLONG_MIN; QHash::const_iterator i = big.constBegin(); while (i != big.constEnd()) { if (i.value() > sMax) { sMax = i.value(); index = i.key(); } ++i; } return index; } //--------------------------------------------------------------------------------------------------------------------- void VBank::SqMaxMin(qint64 &sMax, qint64 &sMin) const { sMax = LLONG_MIN; sMin = LLONG_MAX; QHash::const_iterator i = unsorted.constBegin(); while (i != unsorted.constEnd()) { if (i.value() < sMin) { sMin = i.value(); } if (i.value() > sMax) { sMax = i.value(); } ++i; } } //--------------------------------------------------------------------------------------------------------------------- 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