1 /************************************************************************
2 **
3 ** @file vlayoutpaper.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date 7 1, 2015
6 **
7 ** @brief
8 ** @copyright
9 ** This source code is part of the Valentina project, a pattern making
10 ** program, whose allow create and modeling patterns of clothing.
11 ** Copyright (C) 2013-2015 Valentina project
12 ** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13 **
14 ** Valentina is free software: you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License as published by
16 ** the Free Software Foundation, either version 3 of the License, or
17 ** (at your option) any later version.
18 **
19 ** Valentina is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ** GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
26 **
27 *************************************************************************/
28
29 #include "vlayoutpaper.h"
30
31 #include <QBrush>
32 #include <QCoreApplication>
33 #include <QGraphicsRectItem>
34 #include <QGraphicsScene>
35 #include <QList>
36 #include <QPen>
37 #include <QPointF>
38 #include <QRect>
39 #include <QRectF>
40 #include <QThread>
41 #include <QThreadPool>
42 #include <QVector>
43 #include <Qt>
44 #include <QtAlgorithms>
45
46 #ifdef LAYOUT_DEBUG
47 #include <QMutex>
48 #endif
49
50 #include "vbestsquare.h"
51 #include "vcontour.h"
52 #include "vlayoutpiece.h"
53 #include "vlayoutpaper_p.h"
54 #include "vposition.h"
55 #include "../ifc/exception/vexceptionterminatedposition.h"
56 #include "../vmisc/compatibility.h"
57
58 //---------------------------------------------------------------------------------------------------------------------
VLayoutPaper()59 VLayoutPaper::VLayoutPaper()
60 :d(new VLayoutPaperData)
61 {}
62
63 //---------------------------------------------------------------------------------------------------------------------
VLayoutPaper(int height,int width,qreal layoutWidth)64 VLayoutPaper::VLayoutPaper(int height, int width, qreal layoutWidth)
65 :d(new VLayoutPaperData(height, width, layoutWidth))
66 {}
67
68 //---------------------------------------------------------------------------------------------------------------------
VLayoutPaper(const VLayoutPaper & paper)69 VLayoutPaper::VLayoutPaper(const VLayoutPaper &paper)
70 :d (paper.d)
71 {}
72
73 //---------------------------------------------------------------------------------------------------------------------
operator =(const VLayoutPaper & paper)74 VLayoutPaper &VLayoutPaper::operator=(const VLayoutPaper &paper)
75 {
76 if ( &paper == this )
77 {
78 return *this;
79 }
80 d = paper.d;
81 return *this;
82 }
83
84 #ifdef Q_COMPILER_RVALUE_REFS
85 //---------------------------------------------------------------------------------------------------------------------
VLayoutPaper(const VLayoutPaper && paper)86 VLayoutPaper::VLayoutPaper(const VLayoutPaper &&paper) Q_DECL_NOTHROW
87 :d (paper.d)
88 {}
89
90 //---------------------------------------------------------------------------------------------------------------------
operator =(VLayoutPaper && paper)91 VLayoutPaper &VLayoutPaper::operator=(VLayoutPaper &&paper) Q_DECL_NOTHROW
92 {
93 std::swap(d, paper.d);
94 return *this;
95 }
96 #endif
97
98 //---------------------------------------------------------------------------------------------------------------------
~VLayoutPaper()99 VLayoutPaper::~VLayoutPaper()
100 {}
101
102 //---------------------------------------------------------------------------------------------------------------------
GetHeight() const103 int VLayoutPaper::GetHeight() const
104 {
105 return d->globalContour.GetHeight();
106 }
107
108 //---------------------------------------------------------------------------------------------------------------------
SetHeight(int height)109 void VLayoutPaper::SetHeight(int height)
110 {
111 d->globalContour.SetHeight(height);
112 }
113
114 //---------------------------------------------------------------------------------------------------------------------
GetWidth() const115 int VLayoutPaper::GetWidth() const
116 {
117 return d->globalContour.GetWidth();
118 }
119
120 //---------------------------------------------------------------------------------------------------------------------
SetWidth(int width)121 void VLayoutPaper::SetWidth(int width)
122 {
123 d->globalContour.SetWidth(width);
124 }
125
126 //---------------------------------------------------------------------------------------------------------------------
GetLayoutWidth() const127 qreal VLayoutPaper::GetLayoutWidth() const
128 {
129 return d->layoutWidth;
130 }
131
132 //---------------------------------------------------------------------------------------------------------------------
SetLayoutWidth(qreal width)133 void VLayoutPaper::SetLayoutWidth(qreal width)
134 {
135 if (width >= 0)
136 {
137 d->layoutWidth = width;
138 }
139 }
140
141 //---------------------------------------------------------------------------------------------------------------------
GetShift() const142 qreal VLayoutPaper::GetShift() const
143 {
144 return d->globalContour.GetShift();
145 }
146
147 //---------------------------------------------------------------------------------------------------------------------
SetShift(qreal shift)148 void VLayoutPaper::SetShift(qreal shift)
149 {
150 d->globalContour.SetShift(shift);
151 }
152
153 //---------------------------------------------------------------------------------------------------------------------
GetRotate() const154 bool VLayoutPaper::GetRotate() const
155 {
156 return d->globalRotate;
157 }
158
159 //---------------------------------------------------------------------------------------------------------------------
SetRotate(bool value)160 void VLayoutPaper::SetRotate(bool value)
161 {
162 d->globalRotate = value;
163 d->localRotate = d->globalRotate;
164 }
165
166 //---------------------------------------------------------------------------------------------------------------------
GetFollowGrainline() const167 bool VLayoutPaper::GetFollowGrainline() const
168 {
169 return d->followGrainline;
170 }
171
172 //---------------------------------------------------------------------------------------------------------------------
SetFollowGrainline(bool value)173 void VLayoutPaper::SetFollowGrainline(bool value)
174 {
175 d->followGrainline = value;
176 }
177
178 //---------------------------------------------------------------------------------------------------------------------
GetRotationNumber() const179 int VLayoutPaper::GetRotationNumber() const
180 {
181 return d->globalRotationNumber;
182 }
183
184 //---------------------------------------------------------------------------------------------------------------------
SetRotationNumber(int value)185 void VLayoutPaper::SetRotationNumber(int value)
186 {
187 d->globalRotationNumber = value;
188
189 if (d->globalRotationNumber > 360 || d->globalRotationNumber < 1)
190 {
191 d->globalRotationNumber = 2;
192 }
193
194 d->localRotationNumber = d->globalRotationNumber;
195 }
196
197 //---------------------------------------------------------------------------------------------------------------------
IsSaveLength() const198 bool VLayoutPaper::IsSaveLength() const
199 {
200 return d->saveLength;
201 }
202
203 //---------------------------------------------------------------------------------------------------------------------
SetSaveLength(bool value)204 void VLayoutPaper::SetSaveLength(bool value)
205 {
206 d->saveLength = value;
207 }
208
209 //---------------------------------------------------------------------------------------------------------------------
SetPaperIndex(quint32 index)210 void VLayoutPaper::SetPaperIndex(quint32 index)
211 {
212 d->paperIndex = index;
213 }
214
215 //---------------------------------------------------------------------------------------------------------------------
IsOriginPaperPortrait() const216 bool VLayoutPaper::IsOriginPaperPortrait() const
217 {
218 return d->originPaperOrientation;
219 }
220
221 //---------------------------------------------------------------------------------------------------------------------
SetOriginPaperPortrait(bool portrait)222 void VLayoutPaper::SetOriginPaperPortrait(bool portrait)
223 {
224 d->originPaperOrientation = portrait;
225 }
226
227 //---------------------------------------------------------------------------------------------------------------------
ArrangeDetail(const VLayoutPiece & detail,std::atomic_bool & stop)228 bool VLayoutPaper::ArrangeDetail(const VLayoutPiece &detail, std::atomic_bool &stop)
229 {
230 if (detail.LayoutEdgesCount() < 3 || detail.DetailEdgesCount() < 3)
231 {
232 return false;//Not enough edges
233 }
234
235 if ((detail.IsForceFlipping() || detail.IsForbidFlipping()) && not d->globalRotate)
236 { // Compensate forbidden flipping by rotating. 180 degree will be enough.
237 d->localRotate = true;
238 d->localRotationNumber = 2;
239 }
240 else
241 { // Return to global values if was changed
242 d->localRotate = d->globalRotate;
243 d->localRotationNumber = d->globalRotationNumber;
244 }
245
246 #ifdef LAYOUT_DEBUG
247 QMutex mutex;
248 #endif
249
250 VPositionData data;
251 data.gContour = d->globalContour;
252 data.detail = detail;
253 data.rotate = d->localRotate;
254 data.rotationNumber = d->localRotationNumber;
255 data.followGrainline = d->followGrainline;
256 data.positionsCache = d->positionsCache;
257 data.isOriginPaperOrientationPortrait = d->originPaperOrientation;
258 #ifdef LAYOUT_DEBUG
259 data.details = d->details;
260 data.mutex = &mutex;
261 #endif
262
263 const VBestSquare result = VPosition::ArrangeDetail(data, &stop, d->saveLength);
264 #ifdef LAYOUT_DEBUG
265 return SaveResult(result, detail, &mutex);
266 #else
267 return SaveResult(result, detail);
268 #endif
269 }
270
271 //---------------------------------------------------------------------------------------------------------------------
Count() const272 int VLayoutPaper::Count() const
273 {
274 return d->details.count();
275 }
276
277 //---------------------------------------------------------------------------------------------------------------------
SaveResult(const VBestSquare & bestResult,const VLayoutPiece & detail,QMutex * mutex)278 bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail
279 #ifdef LAYOUT_DEBUG
280 , QMutex *mutex
281 #endif
282 )
283 {
284 if (bestResult.HasValidResult())
285 {
286 VLayoutPiece workDetail = detail;
287 workDetail.SetMatrix(bestResult.Matrix());// Don't forget set matrix
288 workDetail.SetMirror(bestResult.Mirror());
289
290 if (d->saveLength)
291 {
292 d->globalContour.CeateEmptySheetContour();
293 }
294
295 const QVector<QPointF> newGContour = d->globalContour.UniteWithContour(workDetail, bestResult.GContourEdge(),
296 bestResult.DetailEdge(),
297 bestResult.Type());
298 if (newGContour.isEmpty())
299 {
300 return false;
301 }
302 d->details.append(workDetail);
303 d->globalContour.SetContour(newGContour);
304
305 VCachedPositions positionChache;
306 QVector<QPointF> layoutPoints = workDetail.GetLayoutAllowancePoints();
307 positionChache.boundingRect = VLayoutPiece::BoundingRect(layoutPoints);
308 positionChache.layoutAllowancePath = VAbstractPiece::PainterPath(layoutPoints);
309 d->positionsCache.append(positionChache);
310
311 #ifdef LAYOUT_DEBUG
312 # ifdef SHOW_BEST
313 VPosition::DumpFrame(d->globalContour, workDetail, mutex, d->details);
314 # endif
315 #endif
316 }
317 else if (bestResult.IsTerminatedByException())
318 {
319 throw VExceptionTerminatedPosition(bestResult.ReasonTerminatedByException());
320 }
321
322 return bestResult.HasValidResult(); // Do we have the best result?
323 }
324
325 //---------------------------------------------------------------------------------------------------------------------
GetPaperItem(bool autoCropLength,bool autoCropWidth,bool textAsPaths) const326 QGraphicsRectItem *VLayoutPaper::GetPaperItem(bool autoCropLength, bool autoCropWidth, bool textAsPaths) const
327 {
328 int height = d->globalContour.GetHeight();
329 int width = d->globalContour.GetWidth();
330
331 if (autoCropLength || autoCropWidth)
332 {
333 QScopedPointer<QGraphicsScene> scene(new QGraphicsScene());
334 QList<QGraphicsItem *> list = GetItemDetails(textAsPaths);
335 for (auto item : list)
336 {
337 scene->addItem(item);
338 }
339
340 const QRect boundingRect = scene->itemsBoundingRect().toRect();
341
342 if (autoCropLength)
343 {
344 if (d->globalContour.IsPortrait())
345 {
346 height = boundingRect.height() + boundingRect.y() + 1;
347 }
348 else
349 {
350 width = boundingRect.width() + boundingRect.x() + 1;
351 }
352 }
353
354 if (autoCropWidth)
355 {
356 if (d->globalContour.IsPortrait())
357 {
358 width = boundingRect.width() + boundingRect.x() + 1;
359 }
360 else
361 {
362 height = boundingRect.height() + boundingRect.y() + 1;
363 }
364 }
365 }
366
367 auto *paper = new QGraphicsRectItem(QRectF(0, 0, width, height));
368 paper->setPen(QPen(Qt::black, 1));
369 paper->setBrush(QBrush(Qt::white));
370 return paper;
371 }
372
373 //---------------------------------------------------------------------------------------------------------------------
GetGlobalContour() const374 QGraphicsPathItem *VLayoutPaper::GetGlobalContour() const
375 {
376 // contour
377 const QVector<QPointF> points = d->globalContour.GetContour();
378
379 QPainterPath path;
380 if (points.size() > 0)
381 {
382 path.moveTo(points.at(0));
383 for (auto point : points)
384 {
385 path.lineTo(point);
386 }
387 }
388
389 const qreal radius = 1;
390 for (auto point : points)
391 {
392 path.addEllipse(point.x()-radius, point.y()-radius, radius*2, radius*2);
393 }
394
395 for (int i=0; i < points.size()-1; ++i)
396 {
397 QLineF line(points.at(i), points.at(i+1));
398 line.setLength(line.length()/2);
399
400 path.moveTo(line.p2());
401 QLineF side1(line.p2(), line.p1());
402 side1.setAngle(side1.angle()+35);
403 side1.setLength(3);
404 path.lineTo(side1.p2());
405
406 path.moveTo(line.p2());
407 QLineF side2(line.p2(), line.p1());
408 side2.setAngle(side2.angle()-35);
409 side2.setLength(3);
410 path.lineTo(side2.p2());
411 }
412
413 QGraphicsPathItem *item = new QGraphicsPathItem(path);
414 QPen pen = item->pen();
415 pen.setWidthF(0.25);
416 item->setPen(pen);
417
418 return item;
419 }
420
421 //---------------------------------------------------------------------------------------------------------------------
GetItemDetails(bool textAsPaths) const422 QList<QGraphicsItem *> VLayoutPaper::GetItemDetails(bool textAsPaths) const
423 {
424 QList<QGraphicsItem *> list;
425 for (auto &detail : d->details)
426 {
427 list.append(detail.GetItem(textAsPaths));
428 }
429 return list;
430 }
431
432 //---------------------------------------------------------------------------------------------------------------------
GetDetails() const433 QVector<VLayoutPiece> VLayoutPaper::GetDetails() const
434 {
435 return d->details;
436 }
437
438 //---------------------------------------------------------------------------------------------------------------------
SetDetails(const QVector<VLayoutPiece> & details)439 void VLayoutPaper::SetDetails(const QVector<VLayoutPiece> &details)
440 {
441 d->details = details;
442 }
443
444 //---------------------------------------------------------------------------------------------------------------------
SetDetails(const QList<VLayoutPiece> & details)445 void VLayoutPaper::SetDetails(const QList<VLayoutPiece> &details)
446 {
447 d->details = ConvertToVector(details);
448 }
449
450 //---------------------------------------------------------------------------------------------------------------------
DetailsBoundingRect() const451 QRectF VLayoutPaper::DetailsBoundingRect() const
452 {
453 QRectF rec;
454 for (auto &detail : d->details)
455 {
456 rec = rec.united(detail.DetailBoundingRect());
457 }
458
459 return rec;
460 }
461
462 //---------------------------------------------------------------------------------------------------------------------
Efficiency() const463 qreal VLayoutPaper::Efficiency() const
464 {
465 qreal efficiency = 0;
466 for(auto &detail : d->details)
467 {
468 efficiency += static_cast<qreal>(detail.Square());
469 }
470
471 const QRectF boundingRect = DetailsBoundingRect();
472
473 return efficiency / (boundingRect.width() * boundingRect.height()) * 100.0;
474 }
475