valentina/src/libs/vlayout/vlayoutgenerator.cpp
Roman Telezhynskyi 0e3a9533af Refactoring. Use C++11 range-based loop.
--HG--
branch : develop
2018-04-03 14:36:38 +03:00

590 lines
17 KiB
C++

/************************************************************************
**
** @file vlayoutgenerator.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 2 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
** <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vlayoutgenerator.h"
#include <QGraphicsRectItem>
#include <QRectF>
#include <QThreadPool>
#include "../vmisc/def.h"
#include "../vmisc/vmath.h"
#include "vlayoutpiece.h"
#include "vlayoutpaper.h"
//---------------------------------------------------------------------------------------------------------------------
VLayoutGenerator::VLayoutGenerator(QObject *parent)
: QObject(parent),
papers(),
bank(new VBank()),
paperHeight(0),
paperWidth(0),
margins(),
usePrinterFields(true),
#ifdef Q_CC_MSVC
// See https://stackoverflow.com/questions/15750917/initializing-stdatomic-bool
stopGeneration(ATOMIC_VAR_INIT(false)),
#else
stopGeneration(false),
#endif
state(LayoutErrors::NoError),
shift(0),
rotate(true),
rotationIncrease(180),
autoCrop(false),
saveLength(false),
unitePages(false),
stripOptimizationEnabled(false),
multiplier(1),
stripOptimization(false),
textAsPaths(false)
{}
//---------------------------------------------------------------------------------------------------------------------
VLayoutGenerator::~VLayoutGenerator()
{
delete bank;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetDetails(const QVector<VLayoutPiece> &details)
{
bank->SetDetails(details);
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetLayoutWidth(qreal width)
{
bank->SetLayoutWidth(width);
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetCaseType(Cases caseType)
{
bank->SetCaseType(caseType);
}
//---------------------------------------------------------------------------------------------------------------------
// cppcheck-suppress unusedFunction
int VLayoutGenerator::DetailsCount()
{
return bank->AllDetailsCount();
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::Generate()
{
stopGeneration.store(false);
papers.clear();
state = LayoutErrors::NoError;
#ifdef LAYOUT_DEBUG
const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug");
QDir debugDir(path);
debugDir.removeRecursively();
debugDir.mkpath(path);
#endif
emit Start();
if (bank->Prepare())
{
const int width = PageWidth();
int height = PageHeight();
if (stripOptimization)
{
const qreal b = bank->GetBiggestDiagonal() * multiplier + bank->GetLayoutWidth();
if (height >= b*2)
{
stripOptimizationEnabled = true;
height = qFloor(height / qFloor(height/b));
}
}
while (bank->AllDetailsCount() > 0)
{
if (stopGeneration.load())
{
break;
}
VLayoutPaper paper(height, width);
paper.SetShift(shift);
paper.SetLayoutWidth(bank->GetLayoutWidth());
paper.SetPaperIndex(static_cast<quint32>(papers.count()));
paper.SetRotate(rotate);
paper.SetRotationIncrease(rotationIncrease);
paper.SetSaveLength(saveLength);
do
{
const int index = bank->GetTiket();
if (paper.ArrangeDetail(bank->GetDetail(index), stopGeneration))
{
bank->Arranged(index);
emit Arranged(bank->ArrangedCount());
}
else
{
bank->NotArranged(index);
}
if (stopGeneration.load())
{
break;
}
} while(bank->LeftArrange() > 0);
if (stopGeneration.load())
{
break;
}
if (paper.Count() > 0)
{
papers.append(paper);
}
else
{
state = LayoutErrors::EmptyPaperError;
emit Error(state);
return;
}
}
}
else
{
state = LayoutErrors::PrepareLayoutError;
emit Error(state);
return;
}
if (stripOptimizationEnabled)
{
GatherPages();
}
if (IsUnitePages())
{
UnitePages();
}
emit Finished();
}
//---------------------------------------------------------------------------------------------------------------------
LayoutErrors VLayoutGenerator::State() const
{
return state;
}
//---------------------------------------------------------------------------------------------------------------------
QList<QGraphicsItem *> VLayoutGenerator::GetPapersItems() const
{
QList<QGraphicsItem *> list;
for (auto &paper : papers)
{
list.append(paper.GetPaperItem(autoCrop, IsTestAsPaths()));
}
return list;
}
//---------------------------------------------------------------------------------------------------------------------
QList<QList<QGraphicsItem *> > VLayoutGenerator::GetAllDetailsItems() const
{
QList<QList<QGraphicsItem *> > list;
for (auto &paper : papers)
{
list.append(paper.GetItemDetails(IsTestAsPaths()));
}
return list;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QVector<VLayoutPiece> > VLayoutGenerator::GetAllDetails() const
{
QVector<QVector<VLayoutPiece> > list;
for (auto &paper : papers)
{
list.append(paper.GetDetails());
}
return list;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::Abort()
{
stopGeneration.store(true);
state = LayoutErrors::ProcessStoped;
QThreadPool::globalInstance()->clear();
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::IsStripOptimization() const
{
return stripOptimization;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetStripOptimization(bool value)
{
stripOptimization = value;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::IsTestAsPaths() const
{
return textAsPaths;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetTestAsPaths(bool value)
{
textAsPaths = value;
}
//---------------------------------------------------------------------------------------------------------------------
quint8 VLayoutGenerator::GetMultiplier() const
{
return multiplier;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetMultiplier(const quint8 &value)
{
if (value > 10)
{
multiplier = 10;
}
else if (value == 0)
{
multiplier = 1;
}
else
{
multiplier = value;
}
}
//---------------------------------------------------------------------------------------------------------------------
int VLayoutGenerator::PageHeight() const
{
return static_cast<int>(paperHeight - (margins.top() + margins.bottom()));
}
//---------------------------------------------------------------------------------------------------------------------
int VLayoutGenerator::PageWidth() const
{
return static_cast<int>(paperWidth - (margins.left() + margins.right()));
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::GatherPages()
{
if (papers.size() < 2)
{
return;
}
QList<QList<VLayoutPiece>> nDetails;
qreal length = 0;
int j = 0; // papers count
for (int i = 0; i < papers.size(); ++i)
{
int paperHeight = qRound(papers.at(i).DetailsBoundingRect().height());
if (i != papers.size()-1)
{
paperHeight += qRound(bank->GetLayoutWidth()*2);
}
if (length + paperHeight <= PageHeight())
{
UniteDetails(j, nDetails, length, i);
length += paperHeight;
}
else
{
length = 0; // Start new paper
++j;// New paper
UniteDetails(j, nDetails, length, i);
length += paperHeight;
}
}
QVector<VLayoutPaper> nPapers;
for (int i = 0; i < nDetails.size(); ++i)
{
VLayoutPaper paper(PageHeight(), PageWidth());
paper.SetShift(shift);
paper.SetLayoutWidth(bank->GetLayoutWidth());
paper.SetPaperIndex(static_cast<quint32>(i));
paper.SetRotate(rotate);
paper.SetRotationIncrease(rotationIncrease);
paper.SetSaveLength(saveLength);
paper.SetDetails(nDetails.at(i));
nPapers.append(paper);
}
papers.clear();
papers = nPapers;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::UnitePages()
{
if (papers.size() < 2)
{
return;
}
QList<qreal> papersLength;
QList<QList<VLayoutPiece> > nDetails;
qreal length = 0;
int j = 0; // papers count
for (int i = 0; i < papers.size(); ++i)
{
int paperHeight = 0;
if (autoCrop)
{
paperHeight = qRound(papers.at(i).DetailsBoundingRect().height());
}
else
{
paperHeight = papers.at(i).GetHeight();
}
if (i != papers.size()-1)
{
paperHeight = qRound(paperHeight + bank->GetLayoutWidth()*2);
}
if (length + paperHeight <= QIMAGE_MAX)
{
UniteDetails(j, nDetails, length, i);
length += paperHeight;
UnitePapers(j, papersLength, length);
}
else
{
length = 0; // Start new paper
++j;// New paper
UniteDetails(j, nDetails, length, i);
length += paperHeight;
UnitePapers(j, papersLength, length);
}
}
QVector<VLayoutPaper> nPapers;
for (int i = 0; i < nDetails.size(); ++i)
{
VLayoutPaper paper(qFloor(papersLength.at(i)), PageWidth());
paper.SetShift(shift);
paper.SetLayoutWidth(bank->GetLayoutWidth());
paper.SetPaperIndex(static_cast<quint32>(i));
paper.SetRotate(rotate);
paper.SetRotationIncrease(rotationIncrease);
paper.SetSaveLength(saveLength);
paper.SetDetails(nDetails.at(i));
nPapers.append(paper);
}
papers.clear();
papers = nPapers;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::UniteDetails(int j, QList<QList<VLayoutPiece> > &nDetails, qreal length, int i)
{
if ((j == 0 && nDetails.isEmpty()) || j >= nDetails.size())
{//First or new details in paper
nDetails.insert(j, MoveDetails(length, papers.at(i).GetDetails()));
}
else
{
nDetails[j].append(MoveDetails(length, papers.at(i).GetDetails()));
}
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::UnitePapers(int j, QList<qreal> &papersLength, qreal length)
{
if ((j == 0 && papersLength.isEmpty()) || j >= papersLength.size())
{
papersLength.insert(j, length);
}
else
{
papersLength[j] = length;
}
}
//---------------------------------------------------------------------------------------------------------------------
QList<VLayoutPiece> VLayoutGenerator::MoveDetails(qreal length, const QVector<VLayoutPiece> &details)
{
if (qFuzzyIsNull(length))
{
return details.toList();
}
QList<VLayoutPiece> newDetails;
for (auto d : details)
{
d.Translate(0, length);
newDetails.append(d);
}
return newDetails;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::IsUnitePages() const
{
return unitePages;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetUnitePages(bool value)
{
unitePages = value;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::IsSaveLength() const
{
return saveLength;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetSaveLength(bool value)
{
saveLength = value;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::GetAutoCrop() const
{
return autoCrop;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetAutoCrop(bool value)
{
autoCrop = value;
}
//---------------------------------------------------------------------------------------------------------------------
// cppcheck-suppress unusedFunction
int VLayoutGenerator::GetRotationIncrease() const
{
return rotationIncrease;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetRotationIncrease(int value)
{
rotationIncrease = value;
if ((rotationIncrease >= 1 && rotationIncrease <= 180 && 360 % rotationIncrease == 0) == false)
{
rotationIncrease = 180;
}
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::GetRotate() const
{
return rotate;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetRotate(bool value)
{
rotate = value;
}
//---------------------------------------------------------------------------------------------------------------------
qreal VLayoutGenerator::GetPaperWidth() const
{
return paperWidth;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetPaperWidth(qreal value)
{
paperWidth = value;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutGenerator::IsUsePrinterFields() const
{
return usePrinterFields;
}
//---------------------------------------------------------------------------------------------------------------------
QMarginsF VLayoutGenerator::GetPrinterFields() const
{
return margins;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetPrinterFields(bool usePrinterFields, const QMarginsF &value)
{
this->usePrinterFields = usePrinterFields;
margins = value;
}
//---------------------------------------------------------------------------------------------------------------------
quint32 VLayoutGenerator::GetShift() const
{
return shift;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetShift(quint32 shift)
{
this->shift = shift;
}
//---------------------------------------------------------------------------------------------------------------------
qreal VLayoutGenerator::GetPaperHeight() const
{
return paperHeight;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutGenerator::SetPaperHeight(qreal value)
{
paperHeight = value;
}