Seamly2D
Code documentation
vlayoutgenerator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017 Seamly, LLC *
4  * *
5  * https://github.com/fashionfreedom/seamly2d *
6  * *
7  ***************************************************************************
8  **
9  ** Seamly2D is free software: you can redistribute it and/or modify
10  ** it under the terms of the GNU General Public License as published by
11  ** the Free Software Foundation, either version 3 of the License, or
12  ** (at your option) any later version.
13  **
14  ** Seamly2D is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  ** GNU General Public License for more details.
18  **
19  ** You should have received a copy of the GNU General Public License
20  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
21  **
22  **************************************************************************
23 
24  ************************************************************************
25  **
26  ** @file vlayoutgenerator.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date 2 1, 2015
29  **
30  ** @brief
31  ** @copyright
32  ** This source code is part of the Valentine project, a pattern making
33  ** program, whose allow create and modeling patterns of clothing.
34  ** Copyright (C) 2013-2015 Seamly2D project
35  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
36  **
37  ** Seamly2D is free software: you can redistribute it and/or modify
38  ** it under the terms of the GNU General Public License as published by
39  ** the Free Software Foundation, either version 3 of the License, or
40  ** (at your option) any later version.
41  **
42  ** Seamly2D is distributed in the hope that it will be useful,
43  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
44  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45  ** GNU General Public License for more details.
46  **
47  ** You should have received a copy of the GNU General Public License
48  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
49  **
50  *************************************************************************/
51 
52 #include "vlayoutgenerator.h"
53 
54 #include <QGraphicsRectItem>
55 #include <QRectF>
56 #include <QThreadPool>
57 
58 #include "../vmisc/def.h"
59 #include "../vmisc/vmath.h"
60 #include "vlayoutpiece.h"
61 #include "vlayoutpaper.h"
62 
63 //---------------------------------------------------------------------------------------------------------------------
65  : QObject(parent),
66  papers(),
67  bank(new VBank()),
68  paperHeight(0),
69  paperWidth(0),
70  margins(),
71  usePrinterFields(true),
72 #ifdef Q_CC_MSVC
73  // See https://stackoverflow.com/questions/15750917/initializing-stdatomic-bool
74  stopGeneration(ATOMIC_VAR_INIT(false)),
75 #else
76  stopGeneration(false),
77 #endif
78  state(LayoutErrors::NoError),
79  shift(0),
80  rotate(true),
81  rotationIncrease(180),
82  autoCrop(false),
83  saveLength(false),
84  unitePages(false),
85  stripOptimizationEnabled(false),
86  multiplier(1),
87  stripOptimization(false),
88  textAsPaths(false)
89 {}
90 
91 //---------------------------------------------------------------------------------------------------------------------
93 {
94  delete bank;
95 }
96 
97 //---------------------------------------------------------------------------------------------------------------------
99 {
100  bank->setPieces(pieces);
101 }
102 
103 //---------------------------------------------------------------------------------------------------------------------
105 {
106  bank->SetLayoutWidth(width);
107 }
108 
109 //---------------------------------------------------------------------------------------------------------------------
111 {
112  bank->SetCaseType(caseType);
113 }
114 
115 //---------------------------------------------------------------------------------------------------------------------
116 // cppcheck-suppress unusedFunction
118 {
119  return bank->allPieceCount();
120 }
121 
122 //---------------------------------------------------------------------------------------------------------------------
124 {
125  stopGeneration.store(false);
126  papers.clear();
128 
129 #ifdef LAYOUT_DEBUG
130  const QString path = QDir::homePath()+QStringLiteral("/LayoutDebug");
131  QDir debugDir(path);
132  debugDir.removeRecursively();
133  debugDir.mkpath(path);
134 #endif
135 
136  emit Start();
137 
138  if (bank->Prepare())
139  {
140  const int width = PageWidth();
141  int height = PageHeight();
142 
143  if (stripOptimization)
144  {
145  const qreal b = bank->GetBiggestDiagonal() * multiplier + bank->GetLayoutWidth();
146 
147  if (height >= b*2)
148  {
150  height = qFloor(height / qFloor(height/b));
151  }
152  }
153 
154  while (bank->allPieceCount() > 0)
155  {
156  if (stopGeneration.load())
157  {
158  break;
159  }
160 
161  VLayoutPaper paper(height, width);
162  paper.SetShift(shift);
164  paper.SetPaperIndex(static_cast<quint32>(papers.count()));
165  paper.SetRotate(rotate);
167  paper.SetSaveLength(saveLength);
168  do
169  {
170  const int index = bank->GetTiket();
171  if (paper.arrangePiece(bank->getPiece(index), stopGeneration))
172  {
173  bank->Arranged(index);
174  emit Arranged(bank->ArrangedCount());
175  }
176  else
177  {
178  bank->NotArranged(index);
179  }
180 
181  if (stopGeneration.load())
182  {
183  break;
184  }
185  } while(bank->LeftArrange() > 0);
186 
187  if (stopGeneration.load())
188  {
189  break;
190  }
191 
192  if (paper.Count() > 0)
193  {
194  papers.append(paper);
195  }
196  else
197  {
199  emit Error(state);
200  return;
201  }
202  }
203  }
204  else
205  {
207  emit Error(state);
208  return;
209  }
210 
212  {
213  GatherPages();
214  }
215 
216  if (IsUnitePages())
217  {
218  UnitePages();
219  }
220 
221  emit Finished();
222 }
223 
224 //---------------------------------------------------------------------------------------------------------------------
226 {
227  return state;
228 }
229 
230 //---------------------------------------------------------------------------------------------------------------------
232 {
234  for (int i=0; i < papers.count(); ++i)
235  {
236  list.append(papers.at(i).GetPaperItem(autoCrop, IsTestAsPaths()));
237  }
238  return list;
239 }
240 
241 //---------------------------------------------------------------------------------------------------------------------
243 {
245  for (int i=0; i < papers.count(); ++i)
246  {
247  list.append(papers.at(i).getPieceItems(IsTestAsPaths()));
248  }
249  return list;
250 }
251 
252 //---------------------------------------------------------------------------------------------------------------------
254 {
256  for (int i=0; i < papers.count(); ++i)
257  {
258  list.append(papers.at(i).getPieces());
259  }
260  return list;
261 }
262 
263 //---------------------------------------------------------------------------------------------------------------------
265 {
266  stopGeneration.store(true);
268  QThreadPool::globalInstance()->clear();
269 }
270 
271 //---------------------------------------------------------------------------------------------------------------------
273 {
274  return stripOptimization;
275 }
276 
277 //---------------------------------------------------------------------------------------------------------------------
279 {
280  stripOptimization = value;
281 }
282 
283 //---------------------------------------------------------------------------------------------------------------------
285 {
286  return textAsPaths;
287 }
288 
289 //---------------------------------------------------------------------------------------------------------------------
291 {
292  textAsPaths = value;
293 }
294 
295 //---------------------------------------------------------------------------------------------------------------------
297 {
298  return multiplier;
299 }
300 
301 //---------------------------------------------------------------------------------------------------------------------
302 void VLayoutGenerator::SetMultiplier(const quint8 &value)
303 {
304  if (value > 10)
305  {
306  multiplier = 10;
307  }
308  else if (value == 0)
309  {
310  multiplier = 1;
311  }
312  else
313  {
314  multiplier = value;
315  }
316 }
317 
318 //---------------------------------------------------------------------------------------------------------------------
320 {
321  return static_cast<int>(paperHeight - (margins.top() + margins.bottom()));
322 }
323 
324 //---------------------------------------------------------------------------------------------------------------------
326 {
327  return static_cast<int>(paperWidth - (margins.left() + margins.right()));
328 }
329 
330 //---------------------------------------------------------------------------------------------------------------------
332 {
333  if (papers.size() < 2)
334  {
335  return;
336  }
337 
339  qreal length = 0;
340  int j = 0; // papers count
341 
342  for (int i = 0; i < papers.size(); ++i)
343  {
344  int paperHeight = qRound(papers.at(i).piecesBoundingRect().height());
345 
346  if (i != papers.size()-1)
347  {
348  paperHeight += qRound(bank->GetLayoutWidth()*2);
349  }
350 
351  if (length + paperHeight <= PageHeight())
352  {
353  unitePieces(j, pieces, length, i);
354  length += paperHeight;
355  }
356  else
357  {
358  length = 0; // Start new paper
359  ++j;// New paper
360  unitePieces(j, pieces, length, i);
361  length += paperHeight;
362  }
363  }
364 
365  QVector<VLayoutPaper> nPapers;
366  for (int i = 0; i < pieces.size(); ++i)
367  {
368  VLayoutPaper paper(PageHeight(), PageWidth());
369  paper.SetShift(shift);
371  paper.SetPaperIndex(static_cast<quint32>(i));
372  paper.SetRotate(rotate);
374  paper.SetSaveLength(saveLength);
375  paper.setPieces(pieces.at(i));
376 
377  nPapers.append(paper);
378  }
379 
380  papers.clear();
381  papers = nPapers;
382 }
383 
384 //---------------------------------------------------------------------------------------------------------------------
386 {
387  if (papers.size() < 2)
388  {
389  return;
390  }
391 
392  QList<qreal> papersLength;
393  QList<QList<VLayoutPiece> > pieces;
394  qreal length = 0;
395  int j = 0; // papers count
396 
397  for (int i = 0; i < papers.size(); ++i)
398  {
399  int paperHeight = 0;
400  if (autoCrop)
401  {
402  paperHeight = qRound(papers.at(i).piecesBoundingRect().height());
403  }
404  else
405  {
406  paperHeight = papers.at(i).GetHeight();
407  }
408 
409  if (i != papers.size()-1)
410  {
411  paperHeight = qRound(paperHeight + bank->GetLayoutWidth()*2);
412  }
413 
414  if (length + paperHeight <= QIMAGE_MAX)
415  {
416  unitePieces(j, pieces, length, i);
417  length += paperHeight;
418  UnitePapers(j, papersLength, length);
419  }
420  else
421  {
422  length = 0; // Start new paper
423  ++j;// New paper
424  unitePieces(j, pieces, length, i);
425  length += paperHeight;
426  UnitePapers(j, papersLength, length);
427  }
428  }
429 
430  QVector<VLayoutPaper> nPapers;
431  for (int i = 0; i < pieces.size(); ++i)
432  {
433  VLayoutPaper paper(qFloor(papersLength.at(i)), PageWidth());
434  paper.SetShift(shift);
436  paper.SetPaperIndex(static_cast<quint32>(i));
437  paper.SetRotate(rotate);
439  paper.SetSaveLength(saveLength);
440  paper.setPieces(pieces.at(i));
441 
442  nPapers.append(paper);
443  }
444 
445  papers.clear();
446  papers = nPapers;
447 }
448 
449 //---------------------------------------------------------------------------------------------------------------------
450 void VLayoutGenerator::unitePieces(int j, QList<QList<VLayoutPiece> > &pieces, qreal length, int i)
451 {
452  if ((j == 0 && pieces.isEmpty()) || j >= pieces.size())
453  {//First or new pieces in paper
454  pieces.insert(j, movePieces(length, papers.at(i).getPieces()));
455  }
456  else
457  {
458  pieces[j].append(movePieces(length, papers.at(i).getPieces()));
459  }
460 }
461 
462 //---------------------------------------------------------------------------------------------------------------------
463 void VLayoutGenerator::UnitePapers(int j, QList<qreal> &papersLength, qreal length)
464 {
465  if ((j == 0 && papersLength.isEmpty()) || j >= papersLength.size())
466  {
467  papersLength.insert(j, length);
468  }
469  else
470  {
471  papersLength[j] = length;
472  }
473 }
474 
475 //---------------------------------------------------------------------------------------------------------------------
477 {
478  if (qFuzzyIsNull(length))
479  {
480  return pieces.toList();
481  }
482 
483  QList<VLayoutPiece> newPieces;
484  for (int i = 0; i < pieces.size(); ++i)
485  {
486  VLayoutPiece d = pieces.at(i);
487  d.Translate(0, length);
488  newPieces.append(d);
489  }
490 
491  return newPieces;
492 }
493 
494 //---------------------------------------------------------------------------------------------------------------------
496 {
497  return unitePages;
498 }
499 
500 //---------------------------------------------------------------------------------------------------------------------
502 {
503  unitePages = value;
504 }
505 
506 //---------------------------------------------------------------------------------------------------------------------
508 {
509  return saveLength;
510 }
511 
512 //---------------------------------------------------------------------------------------------------------------------
514 {
515  saveLength = value;
516 }
517 
518 //---------------------------------------------------------------------------------------------------------------------
520 {
521  return autoCrop;
522 }
523 
524 //---------------------------------------------------------------------------------------------------------------------
526 {
527  autoCrop = value;
528 }
529 
530 //---------------------------------------------------------------------------------------------------------------------
531 // cppcheck-suppress unusedFunction
533 {
534  return rotationIncrease;
535 }
536 
537 //---------------------------------------------------------------------------------------------------------------------
539 {
540  rotationIncrease = value;
541 
542  if ((rotationIncrease >= 1 && rotationIncrease <= 180 && 360 % rotationIncrease == 0) == false)
543  {
544  rotationIncrease = 180;
545  }
546 }
547 
548 //---------------------------------------------------------------------------------------------------------------------
550 {
551  return rotate;
552 }
553 
554 //---------------------------------------------------------------------------------------------------------------------
556 {
557  rotate = value;
558 }
559 
560 //---------------------------------------------------------------------------------------------------------------------
562 {
563  return paperWidth;
564 }
565 
566 //---------------------------------------------------------------------------------------------------------------------
568 {
569  paperWidth = value;
570 }
571 
572 //---------------------------------------------------------------------------------------------------------------------
574 {
575  return usePrinterFields;
576 }
577 
578 //---------------------------------------------------------------------------------------------------------------------
580 {
581  return margins;
582 }
583 
584 //---------------------------------------------------------------------------------------------------------------------
585 void VLayoutGenerator::SetPrinterFields(bool usePrinterFields, const QMarginsF &value)
586 {
587  this->usePrinterFields = usePrinterFields;
588  margins = value;
589 }
590 
591 //---------------------------------------------------------------------------------------------------------------------
593 {
594  return shift;
595 }
596 
597 //---------------------------------------------------------------------------------------------------------------------
598 void VLayoutGenerator::SetShift(quint32 shift)
599 {
600  this->shift = shift;
601 }
602 
603 //---------------------------------------------------------------------------------------------------------------------
605 {
606  return paperHeight;
607 }
608 
609 //---------------------------------------------------------------------------------------------------------------------
611 {
612  paperHeight = value;
613 }
@ NoError
Definition: abstracttest.h:79
Definition: vbank.h:74
int LeftArrange() const
Definition: vbank.cpp:269
void SetCaseType(Cases caseType)
Definition: vbank.cpp:257
void SetLayoutWidth(const qreal &value)
Definition: vbank.cpp:96
int ArrangedCount() const
Definition: vbank.cpp:281
int allPieceCount() const
Definition: vbank.cpp:263
VLayoutPiece getPiece(int i) const
Definition: vbank.cpp:143
void setPieces(const QVector< VLayoutPiece > &pieces)
Definition: vbank.cpp:103
qreal GetLayoutWidth() const
Definition: vbank.cpp:90
int GetTiket()
Definition: vbank.cpp:110
void Arranged(int i)
Definition: vbank.cpp:156
qreal GetBiggestDiagonal() const
Definition: vbank.cpp:275
bool Prepare()
Definition: vbank.cpp:201
void NotArranged(int i)
Definition: vbank.cpp:177
qreal GetPaperHeight() const
void SetPaperHeight(qreal value)
void SetLayoutWidth(qreal width)
void SetPaperWidth(qreal value)
Q_REQUIRED_RESULT QList< QGraphicsItem * > GetPapersItems() const
void SetAutoCrop(bool value)
void Arranged(int count)
void setPieces(const QVector< VLayoutPiece > &details)
int GetRotationIncrease() const
void SetUnitePages(bool value)
quint8 GetMultiplier() const
void UnitePapers(int j, QList< qreal > &papersLength, qreal length)
void SetRotationIncrease(int value)
QList< VLayoutPiece > movePieces(qreal length, const QVector< VLayoutPiece > &pieces)
Q_REQUIRED_RESULT QList< QList< QGraphicsItem * > > getAllPieceItems() const
bool IsUnitePages() const
void SetRotate(bool value)
void SetTestAsPaths(bool value)
virtual ~VLayoutGenerator() Q_DECL_OVERRIDE
void SetPrinterFields(bool usePrinterFields, const QMarginsF &value)
bool GetAutoCrop() const
bool IsSaveLength() const
void SetCaseType(Cases caseType)
qreal GetPaperWidth() const
void unitePieces(int j, QList< QList< VLayoutPiece > > &pieces, qreal length, int i)
QMarginsF GetPrinterFields() const
LayoutErrors state
bool GetRotate() const
void SetMultiplier(const quint8 &value)
std::atomic_bool stopGeneration
void SetStripOptimization(bool value)
void SetShift(quint32 shift)
LayoutErrors State() const
void Error(const LayoutErrors &state)
bool IsTestAsPaths() const
QVector< VLayoutPaper > papers
bool IsStripOptimization() const
quint32 GetShift() const
VLayoutGenerator(QObject *parent=nullptr)
QVector< QVector< VLayoutPiece > > getAllPieces() const
void SetSaveLength(bool value)
bool IsUsePrinterFields() const
bool arrangePiece(const VLayoutPiece &piece, std::atomic_bool &stop)
void setPieces(const QList< VLayoutPiece > &pieces)
void SetRotationIncrease(int value)
void SetShift(quint32 shift)
void SetSaveLength(bool value)
void SetRotate(bool value)
int Count() const
void SetPaperIndex(quint32 index)
void SetLayoutWidth(qreal width)
void Translate(qreal dx, qreal dy)
#define QIMAGE_MAX
Definition: def.h:298
Cases
Definition: vbank.h:71
LayoutErrors
Definition: vlayoutdef.h:60