Seamly2D
Code documentation
vlayoutpaper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ** @file vlayoutpaper.cpp
3  ** @author Douglas S Caskey
4  ** @date Dec 27, 2022
5  **
6  ** @copyright
7  ** Copyright (C) 2017 - 2022 Seamly, LLC
8  ** https://github.com/fashionfreedom/seamly2d
9  **
10  ** @brief
11  ** Seamly2D is free software: you can redistribute it and/or modify
12  ** it under the terms of the GNU General Public License as published by
13  ** the Free Software Foundation, either version 3 of the License, or
14  ** (at your option) any later version.
15  **
16  ** Seamly2D is distributed in the hope that it will be useful,
17  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  ** GNU General Public License for more details.
20  **
21  ** You should have received a copy of the GNU General Public License
22  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
23  **************************************************************************/
24 
25 /************************************************************************
26  **
27  ** @file vlayoutpaper.cpp
28  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
29  ** @date 7 1, 2015
30  **
31  ** @brief
32  ** @copyright
33  ** This source code is part of the Valentina project, a pattern making
34  ** program, whose allow create and modeling patterns of clothing.
35  ** Copyright (C) 2013-2015 Valentina project
36  ** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
37  **
38  ** Valentina is free software: you can redistribute it and/or modify
39  ** it under the terms of the GNU General Public License as published by
40  ** the Free Software Foundation, either version 3 of the License, or
41  ** (at your option) any later version.
42  **
43  ** Valentina is distributed in the hope that it will be useful,
44  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
45  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46  ** GNU General Public License for more details.
47  **
48  ** You should have received a copy of the GNU General Public License
49  ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
50  **
51  *************************************************************************/
52 
53 #include "vlayoutpaper.h"
54 
55 #include <QBrush>
56 #include <QCoreApplication>
57 #include <QGraphicsRectItem>
58 #include <QGraphicsScene>
59 #include <QList>
60 #include <QPen>
61 #include <QPointF>
62 #include <QRect>
63 #include <QRectF>
64 #include <QThread>
65 #include <QThreadPool>
66 #include <QVector>
67 #include <Qt>
68 #include <QtAlgorithms>
69 
70 #include "vbestsquare.h"
71 #include "vcontour.h"
72 #include "vlayoutpiece.h"
73 #include "vlayoutpaper_p.h"
74 #include "vposition.h"
75 
76 #ifdef Q_COMPILER_RVALUE_REFS
77 VLayoutPaper &VLayoutPaper::operator=(VLayoutPaper &&paper) Q_DECL_NOTHROW { Swap(paper); return *this; }
78 #endif
79 
80 void VLayoutPaper::Swap(VLayoutPaper &paper) Q_DECL_NOTHROW
81 { std::swap(d, paper.d); }
82 
83 //---------------------------------------------------------------------------------------------------------------------
85  :d(new VLayoutPaperData)
86 {}
87 
88 //---------------------------------------------------------------------------------------------------------------------
89 VLayoutPaper::VLayoutPaper(int height, int width)
90  :d(new VLayoutPaperData(height, width))
91 {}
92 
93 //---------------------------------------------------------------------------------------------------------------------
95  :d (paper.d)
96 {}
97 
98 //---------------------------------------------------------------------------------------------------------------------
100 {
101  if ( &paper == this )
102  {
103  return *this;
104  }
105  d = paper.d;
106  return *this;
107 }
108 
109 //---------------------------------------------------------------------------------------------------------------------
111 {}
112 
113 //---------------------------------------------------------------------------------------------------------------------
115 {
116  return d->globalContour.GetHeight();
117 }
118 
119 //---------------------------------------------------------------------------------------------------------------------
120 void VLayoutPaper::SetHeight(int height)
121 {
122  d->globalContour.SetHeight(height);
123 }
124 
125 //---------------------------------------------------------------------------------------------------------------------
127 {
128  return d->globalContour.GetWidth();
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
132 void VLayoutPaper::SetWidth(int width)
133 {
134  d->globalContour.SetWidth(width);
135 }
136 
137 //---------------------------------------------------------------------------------------------------------------------
139 {
140  return d->layoutWidth;
141 }
142 
143 //---------------------------------------------------------------------------------------------------------------------
145 {
146  if (width >= 0)
147  {
148  d->layoutWidth = width;
149  }
150 }
151 
152 //---------------------------------------------------------------------------------------------------------------------
153 quint32 VLayoutPaper::GetShift() const
154 {
155  return d->globalContour.GetShift();
156 }
157 
158 //---------------------------------------------------------------------------------------------------------------------
159 void VLayoutPaper::SetShift(quint32 shift)
160 {
161  d->globalContour.SetShift(shift);
162 }
163 
164 //---------------------------------------------------------------------------------------------------------------------
166 {
167  return d->globalRotate;
168 }
169 
170 //---------------------------------------------------------------------------------------------------------------------
171 void VLayoutPaper::SetRotate(bool value)
172 {
173  d->globalRotate = value;
174  d->localRotate = d->globalRotate;
175 }
176 
177 //---------------------------------------------------------------------------------------------------------------------
179 {
180  return d->globalRotationIncrease;
181 }
182 
183 //---------------------------------------------------------------------------------------------------------------------
185 {
186  d->globalRotationIncrease = value;
187 
188  if ((d->globalRotationIncrease >= 1
189  && d->globalRotationIncrease <= 180
190  && 360 % d->globalRotationIncrease == 0) == false)
191  {
192  d->globalRotationIncrease = 180;
193  }
194 
195  d->localRotationIncrease = d->globalRotationIncrease;
196 }
197 
198 //---------------------------------------------------------------------------------------------------------------------
200 {
201  return d->saveLength;
202 }
203 
204 //---------------------------------------------------------------------------------------------------------------------
206 {
207  d->saveLength = value;
208 }
209 
210 //---------------------------------------------------------------------------------------------------------------------
211 void VLayoutPaper::SetPaperIndex(quint32 index)
212 {
213  d->paperIndex = index;
214 }
215 
216 //---------------------------------------------------------------------------------------------------------------------
217 bool VLayoutPaper::arrangePiece(const VLayoutPiece &piece, std::atomic_bool &stop)
218 {
219  // First need set size of paper
220  if (d->globalContour.GetHeight() <= 0 || d->globalContour.GetWidth() <= 0)
221  {
222  return false;
223  }
224 
225  if (piece.LayoutEdgesCount() < 3 || piece.pieceEdgesCount() < 3)
226  {
227  return false;//Not enough edges
228  }
229 
230  if (piece.IsForbidFlipping() && not d->globalRotate)
231  { // Compensate forbidden flipping by rotating. 180 degree will be enough.
232  d->localRotate = true;
233  d->localRotationIncrease = 180;
234  }
235  else
236  { // Return to global values if was changed
237  d->localRotate = d->globalRotate;
238  d->localRotationIncrease = d->globalRotationIncrease;
239  }
240 
241  d->frame = 0;
242 
243  return AddToSheet(piece, stop);
244 }
245 
246 //---------------------------------------------------------------------------------------------------------------------
248 {
249  return d->pieces.count();
250 }
251 
252 //---------------------------------------------------------------------------------------------------------------------
253 bool VLayoutPaper::AddToSheet(const VLayoutPiece &piece, std::atomic_bool &stop)
254 {
255  VBestSquare bestResult(d->globalContour.GetSize(), d->saveLength);
256  QThreadPool *thread_pool = QThreadPool::globalInstance();
257  thread_pool->setExpiryTimeout(1000);
258  QVector<VPosition *> threads;
259 
260  int pieceEdgesCount = 0;
261 
262  if (d->globalContour.GetContour().isEmpty())
263  {
264  pieceEdgesCount = piece.pieceEdgesCount();
265  }
266  else
267  {
268  pieceEdgesCount = piece.LayoutEdgesCount();
269  }
270 
271  for (int j=1; j <= d->globalContour.GlobalEdgesCount(); ++j)
272  {
273  for (int i=1; i<= pieceEdgesCount; ++i)
274  {
275  VPosition *thread = new VPosition(d->globalContour, j, piece, i, &stop, d->localRotate,
276  d->localRotationIncrease,
277  d->saveLength);
278  //Info for debug
279  #ifdef LAYOUT_DEBUG
280  thread->setPaperIndex(d->paperIndex);
281  thread->setFrame(d->frame);
282  thread->setPieceCount(d->pieces.count());
283  thread->setPieces(d->pieces);
284  #endif
285 
286  thread->setAutoDelete(false);
287  threads.append(thread);
288  thread_pool->start(thread);
289 
290  d->frame = d->frame + 3 + static_cast<quint32>(360/d->localRotationIncrease*2);
291  }
292  }
293 
294  // Wait for done
295  do
296  {
297  QCoreApplication::processEvents();
298  QThread::msleep(250);
299  }
300  while(thread_pool->activeThreadCount() > 0 && not stop.load());
301 
302  if (stop.load())
303  {
304  qDeleteAll(threads.begin(), threads.end());
305  threads.clear();
306  return false;
307  }
308 
309  for (int i=0; i < threads.size(); ++i)
310  {
311  bestResult.NewResult(threads.at(i)->getBestResult());
312  }
313 
314  qDeleteAll(threads.begin(), threads.end());
315  threads.clear();
316 
317  return SaveResult(bestResult, piece);
318 }
319 
320 //---------------------------------------------------------------------------------------------------------------------
321 bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece &piece)
322 {
323  if (bestResult.ValidResult())
324  {
325  VLayoutPiece workDetail = piece;
326  workDetail.setTransform(bestResult.Transform());// Don't forget set transform
327  workDetail.SetMirror(bestResult.isMirror());
328  const QVector<QPointF> newGContour = d->globalContour.UniteWithContour(workDetail, bestResult.GContourEdge(),
329  bestResult.pieceEdge(),
330  bestResult.Type());
331  if (newGContour.isEmpty())
332  {
333  return false;
334  }
335  d->pieces.append(workDetail);
336  d->globalContour.SetContour(newGContour);
337 
338 #ifdef LAYOUT_DEBUG
339 # ifdef SHOW_BEST
340  VPosition::DrawDebug(d->globalContour, workDetail, UINT_MAX, d->paperIndex, d->pieces.count(), d->pieces);
341 # endif
342 #endif
343  }
344 
345  return bestResult.ValidResult(); // Do we have the best result?
346 }
347 
348 //---------------------------------------------------------------------------------------------------------------------
349 QGraphicsRectItem *VLayoutPaper::GetPaperItem(bool autoCrop, bool textAsPaths) const
350 {
351  QGraphicsRectItem *paper;
352  if (autoCrop)
353  {
354  QScopedPointer<QGraphicsScene> scene(new QGraphicsScene());
355  QList<QGraphicsItem *> list = getPieceItems(textAsPaths);
356  for (int i=0; i < list.size(); ++i)
357  {
358  scene->addItem(list.at(i));
359  }
360  const int height = scene->itemsBoundingRect().toRect().height();
361  if (d->globalContour.GetHeight() > height) //-V807
362  {
363  paper = new QGraphicsRectItem(QRectF(0, 0, d->globalContour.GetWidth(), height));
364  }
365  else
366  {
367  paper = new QGraphicsRectItem(QRectF(0, 0, d->globalContour.GetWidth(), d->globalContour.GetHeight()));
368  }
369  }
370  else
371  {
372  paper = new QGraphicsRectItem(QRectF(0, 0, d->globalContour.GetWidth(), d->globalContour.GetHeight()));
373  }
374  paper->setPen(QPen(Qt::black, 1));
375  paper->setBrush(QBrush(Qt::white));
376  return paper;
377 }
378 
379 //---------------------------------------------------------------------------------------------------------------------
381 {
383  for (int i=0; i < d->pieces.count(); ++i)
384  {
385  list.append(d->pieces.at(i).GetItem(textAsPaths));
386  }
387  return list;
388 }
389 
390 //---------------------------------------------------------------------------------------------------------------------
392 {
393  return d->pieces;
394 }
395 
396 //---------------------------------------------------------------------------------------------------------------------
398 {
399  d->pieces = pieces.toVector();
400 }
401 
402 //---------------------------------------------------------------------------------------------------------------------
404 {
405  QRectF rec;
406  for (int i=0; i < d->pieces.count(); ++i)
407  {
408  rec = rec.united(d->pieces.at(i).pieceBoundingRect());
409  }
410 
411  return rec;
412 }
bool IsForbidFlipping() const
bool ValidResult() const
int GContourEdge() const
QTransform Transform() const
bool isMirror() const
BestFrom Type() const
int pieceEdge() const
void NewResult(const QSizeF &candidate, int i, int j, const QTransform &transform, bool mirror, BestFrom type)
Definition: vbestsquare.cpp:69
VLayoutPaper & operator=(const VLayoutPaper &paper)
bool arrangePiece(const VLayoutPiece &piece, std::atomic_bool &stop)
void setPieces(const QList< VLayoutPiece > &pieces)
quint32 GetShift() const
bool SaveResult(const VBestSquare &bestResult, const VLayoutPiece &piece)
void SetRotationIncrease(int value)
void Swap(VLayoutPaper &paper) Q_DECL_NOTHROW
void SetShift(quint32 shift)
QRectF piecesBoundingRect() const
void SetSaveLength(bool value)
void SetRotate(bool value)
int Count() const
void SetWidth(int width)
int GetHeight() const
QVector< VLayoutPiece > getPieces() const
void SetHeight(int height)
void SetPaperIndex(quint32 index)
bool AddToSheet(const VLayoutPiece &piece, std::atomic_bool &stop)
int GetWidth() const
int GetRotationIncrease() const
void SetLayoutWidth(qreal width)
bool GetRotate() const
Q_REQUIRED_RESULT QList< QGraphicsItem * > getPieceItems(bool textAsPaths) const
bool IsSaveLength() const
qreal GetLayoutWidth() const
Q_REQUIRED_RESULT QGraphicsRectItem * GetPaperItem(bool autoCrop, bool textAsPaths) const
QSharedDataPointer< VLayoutPaperData > d
Definition: vlayoutpaper.h:123
int pieceEdgesCount() const
int LayoutEdgesCount() const
void setTransform(const QTransform &transform)
void SetMirror(bool value)
static void DrawDebug(const VContour &contour, const VLayoutPiece &piece, int frame, quint32 paperIndex, int piecesCount, const QVector< VLayoutPiece > &pieces=QVector< VLayoutPiece >())
Definition: vposition.cpp:189
void setPieces(const QVector< VLayoutPiece > &pieces)
Definition: vposition.cpp:177
void setFrame(const quint32 &value)
Definition: vposition.cpp:158
void setPaperIndex(const quint32 &value)
Definition: vposition.cpp:145
void setPieceCount(const quint32 &value)
Definition: vposition.cpp:171