Seamly2D
Code documentation
vpiecepath.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ** @file vpiecepath.cpp
3  ** @author Douglas S Caskey
4  ** @date Dec 11, 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
28  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
29  ** @date 22 11, 2016
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) 2016 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 "vpiecepath.h"
54 #include "vpiecepath_p.h"
55 #include "vcontainer.h"
56 #include "../vgeometry/vpointf.h"
57 #include "../vlayout/vabstractpiece.h"
58 
59 #include <QPainterPath>
60 
61 namespace
62 {
63 //---------------------------------------------------------------------------------------------------------------------
64 VSAPoint CurvePoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node,
65  const QVector<QPointF> &curvePoints)
66 {
67  if (node.GetTypeTool() == Tool::NodePoint)
68  {
69  const QPointF p = static_cast<QPointF>(*data->GeometricObject<VPointF>(node.GetId()));
70  if (VAbstractCurve::isPointOnCurve(curvePoints, p))
71  {
72  candidate = VSAPoint(p);
73  candidate.SetSAAfter(node.GetSAAfter(data, *data->GetPatternUnit()));
74  candidate.SetSABefore(node.GetSABefore(data, *data->GetPatternUnit()));
75  candidate.SetAngleType(node.GetAngleType());
76  }
77  }
78  return candidate;
79 }
80 
81 //---------------------------------------------------------------------------------------------------------------------
82 VSAPoint CurveStartPoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node,
83  const QVector<QPointF> &curvePoints)
84 {
85  if (node.GetTypeTool() == Tool::NodePoint)
86  {
87  return CurvePoint(candidate, data, node, curvePoints);
88  }
89  else
90  {
91  // See issue #620. Detail path not correct. Previous curve also should cut segment.
93 
94  const QVector<QPointF> points = curve->getPoints();
95  if (!points.isEmpty())
96  {
97  QPointF end; // Last point for this curve show start of next segment
98  node.GetReverse() ? end = points.first() : end = points.last();
99  if (VAbstractCurve::isPointOnCurve(curvePoints, end))
100  {
101  candidate = VSAPoint(end);
102  }
103  }
104  }
105  return candidate;
106 }
107 
108 //---------------------------------------------------------------------------------------------------------------------
109 VSAPoint CurveEndPoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node,
110  const QVector<QPointF> &curvePoints)
111 {
112  if (node.GetTypeTool() == Tool::NodePoint)
113  {
114  return CurvePoint(candidate, data, node, curvePoints);
115  }
116  else
117  {
118  // See issue #620. Detail path not correct. Previous curve also should cut segment.
120 
121  const QVector<QPointF> points = curve->getPoints();
122  if (!points.isEmpty())
123  {
124  QPointF begin;// First point for this curve show finish of previous segment
125  node.GetReverse() ? begin = points.last() : begin = points.first();
126  if (VAbstractCurve::isPointOnCurve(curvePoints, begin))
127  {
128  candidate = VSAPoint(begin);
129  }
130  }
131  }
132  return candidate;
133 }
134 
135 //---------------------------------------------------------------------------------------------------------------------
136 /**
137  * @brief indexOfNode return index in list node using id object.
138  * @param list list nodes detail.
139  * @param id object (arc, point, spline, splinePath) id.
140  * @return index in list or -1 id can't find.
141  */
142 int IndexOfNode(const QVector<VPieceNode> &list, quint32 id)
143 {
144  for (int i = 0; i < list.size(); ++i)
145  {
146  if (list.at(i).GetId() == id)
147  {
148  return i;
149  }
150  }
151  qDebug()<<"Can't find node.";
152  return -1;
153 }
154 }
155 
156 //---------------------------------------------------------------------------------------------------------------------
157 
158 #ifdef Q_COMPILER_RVALUE_REFS
159 VPiecePath &VPiecePath::operator=(VPiecePath &&path) Q_DECL_NOTHROW
160 { Swap(path); return *this; }
161 #endif
162 
163 void VPiecePath::Swap(VPiecePath &path) Q_DECL_NOTHROW
164 { std::swap(d, path.d); }
165 
166 //---------------------------------------------------------------------------------------------------------------------
168  : d(new VPiecePathData)
169 {}
170 
171 //---------------------------------------------------------------------------------------------------------------------
173  : d(new VPiecePathData(type))
174 {}
175 
176 //---------------------------------------------------------------------------------------------------------------------
178  : d (path.d)
179 {}
180 
181 //---------------------------------------------------------------------------------------------------------------------
183 {
184  if ( &path == this )
185  {
186  return *this;
187  }
188  d = path.d;
189  return *this;
190 }
191 
192 //---------------------------------------------------------------------------------------------------------------------
194 {}
195 
196 //---------------------------------------------------------------------------------------------------------------------
198 {
199  d->m_nodes.append(node);
200 }
201 
202 //---------------------------------------------------------------------------------------------------------------------
204 {
205  d->m_nodes.clear();
206 }
207 
208 //---------------------------------------------------------------------------------------------------------------------
210 {
211  return d->m_nodes.size();
212 }
213 
214 //---------------------------------------------------------------------------------------------------------------------
216 {
217  return d->m_nodes[indx];
218 }
219 
220 //---------------------------------------------------------------------------------------------------------------------
221 const VPieceNode &VPiecePath::at(int indx) const
222 {
223  return d->m_nodes.at(indx);
224 }
225 
226 //---------------------------------------------------------------------------------------------------------------------
228 {
229  return d->m_nodes;
230 }
231 
232 //---------------------------------------------------------------------------------------------------------------------
234 {
235  d->m_nodes = nodes;
236 }
237 
238 //---------------------------------------------------------------------------------------------------------------------
240 {
241  return d->m_type;
242 }
243 
244 //---------------------------------------------------------------------------------------------------------------------
246 {
247  d->m_type = type;
248 }
249 
250 //---------------------------------------------------------------------------------------------------------------------
251 QString VPiecePath::GetName() const
252 {
253  return d->m_name;
254 }
255 
256 //---------------------------------------------------------------------------------------------------------------------
257 void VPiecePath::SetName(const QString &name)
258 {
259  d->m_name = name;
260 }
261 
262 //---------------------------------------------------------------------------------------------------------------------
263 Qt::PenStyle VPiecePath::GetPenType() const
264 {
265  return d->m_penType;
266 }
267 
268 //---------------------------------------------------------------------------------------------------------------------
269 void VPiecePath::SetPenType(const Qt::PenStyle &type)
270 {
271  d->m_penType = type;
272 }
273 
274 //---------------------------------------------------------------------------------------------------------------------
276 {
277  return d->m_cut;
278 }
279 
280 //---------------------------------------------------------------------------------------------------------------------
282 {
283  d->m_cut = cut;
284 }
285 
286 //---------------------------------------------------------------------------------------------------------------------
288 {
289  QVector<QPointF> points;
290  for (int i = 0; i < CountNodes(); ++i)
291  {
292  if (at(i).isExcluded())
293  {
294  continue;// skip excluded node
295  }
296 
297  switch (at(i).GetTypeTool())
298  {
299  case (Tool::NodePoint):
300  {
301  const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).GetId());
302  points.append(static_cast<QPointF>(*point));
303  }
304  break;
305  case (Tool::NodeArc):
306  case (Tool::NodeElArc):
307  case (Tool::NodeSpline):
308  case (Tool::NodeSplinePath):
309  {
311 
312  const QPointF begin = StartSegment(data, i, at(i).GetReverse());
313  const QPointF end = EndSegment(data, i, at(i).GetReverse());
314 
315  points << curve->GetSegmentPoints(begin, end, at(i).GetReverse());
316  }
317  break;
318  default:
319  qDebug() << "Got wrong tool type. Ignore." << static_cast<char>(at(i).GetTypeTool());
320  break;
321  }
322  }
323 
324  return points;
325 }
326 
327 //---------------------------------------------------------------------------------------------------------------------
328 QVector<VPointF> VPiecePath::PathNodePoints(const VContainer *data, bool showExcluded) const
329 {
330  QVector<VPointF> points;
331  for (int i = 0; i < CountNodes(); ++i)
332  {
333  switch (at(i).GetTypeTool())
334  {
335  case Tool::NodePoint:
336  {
337  if (showExcluded || not at(i).isExcluded())
338  {
339  const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).GetId());
340  points.append(*point);
341  }
342  }
343  break;
344  case Tool::NodeArc:
345  case Tool::NodeElArc:
346  case Tool::NodeSpline:
348  default:
349  break;
350  }
351  }
352 
353  return points;
354 }
355 
356 //---------------------------------------------------------------------------------------------------------------------
357 QVector<VSAPoint> VPiecePath::SeamAllowancePoints(const VContainer *data, qreal width, bool reverse) const
358 {
359  SCASSERT(data != nullptr);
360 
361  QVector<VSAPoint> pointsEkv;
362  for (int i = 0; i< d->m_nodes.size(); ++i)
363  {
364  const VPieceNode &node = d->m_nodes.at(i);
365  switch (node.GetTypeTool())
366  {
367  case (Tool::NodePoint):
368  {
369  pointsEkv.append(PreparePointEkv(node, data));
370  }
371  break;
372  case (Tool::NodeArc):
373  case (Tool::NodeElArc):
374  case (Tool::NodeSpline):
375  case (Tool::NodeSplinePath):
376  {
378  pointsEkv += CurveSeamAllowanceSegment(data, d->m_nodes, curve, i, node.GetReverse(), width);
379  }
380  break;
381  default:
382  qDebug() << "Got wrong tool type. Ignore." << static_cast<char>(node.GetTypeTool());
383  break;
384  }
385  }
386 
387  if (reverse)
388  {
389  pointsEkv = VGObject::GetReversePoints(pointsEkv);
390  }
391 
392  return pointsEkv;
393 }
394 
395 //---------------------------------------------------------------------------------------------------------------------
396 QPainterPath VPiecePath::PainterPath(const VContainer *data) const
397 {
398  const QVector<QPointF> points = PathPoints(data);
399  QPainterPath path;
400 
401  if (!points.isEmpty())
402  {
403  path.addPolygon(QPolygonF(points));
404  path.setFillRule(Qt::WindingFill);
405  }
406 
407  return path;
408 }
409 
410 //---------------------------------------------------------------------------------------------------------------------
411 VSAPoint VPiecePath::StartSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse)
412 {
413  if (i < 0 || i > nodes.size()-1)
414  {
415  return VSAPoint();
416  }
417 
418  const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(nodes.at(i).GetId());
419 
420  const QVector<QPointF> points = curve->getPoints();
421  if (points.isEmpty())
422  {
423  return VSAPoint();
424  }
425 
426  VSAPoint begin;
427  reverse ? begin = VSAPoint(points.last()) : begin = VSAPoint(points.first());
428 
429  if (nodes.size() > 1)
430  {
431  const int index = FindInLoopNotExcludedUp(i, nodes);
432 
433  if (index != i && index != -1)
434  {
435  begin = CurveStartPoint(begin, data, nodes.at(index), points);
436  }
437  }
438  return begin;
439 }
440 
441 //---------------------------------------------------------------------------------------------------------------------
442 VSAPoint VPiecePath::EndSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse)
443 {
444  if (i < 0 || i > nodes.size()-1)
445  {
446  return VSAPoint();
447  }
448 
449  const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(nodes.at(i).GetId());
450 
451  const QVector<QPointF> points = curve->getPoints();
452  if (points.isEmpty())
453  {
454  return VSAPoint();
455  }
456 
457  VSAPoint end;
458  reverse ? end = VSAPoint(points.first()) : end = VSAPoint(points.last());
459 
460  if (nodes.size() > 2)
461  {
462  const int index = FindInLoopNotExcludedDown(i, nodes);
463 
464  if (index != i && index != -1)
465  {
466  end = CurveEndPoint(end, data, nodes.at(index), points);
467  }
468  }
469  return end;
470 }
471 
472 //---------------------------------------------------------------------------------------------------------------------
474 {
475  if (d->m_nodes.size() == path.CountNodes()) //-V807
476  {
477  return QVector<quint32>();
478  }
479 
480  QSet<quint32> set1;
481  for (qint32 i = 0; i < d->m_nodes.size(); ++i)
482  {
483  set1.insert(d->m_nodes.at(i).GetId());
484  }
485 
486  QSet<quint32> set2;
487  for (qint32 j = 0; j < path.CountNodes(); ++j)
488  {
489  set2.insert(path.at(j).GetId());
490  }
491 
492  const QList<quint32> set3 = set1.subtract(set2).values();
493  QVector<quint32> nodes;
494  for (qint32 i = 0; i < set3.size(); ++i)
495  {
496  const int index = indexOfNode(set3.at(i));
497  if (index != -1)
498  {
499  nodes.append(d->m_nodes.at(index).GetId());
500  }
501  }
502 
503  return nodes;
504 }
505 
506 //---------------------------------------------------------------------------------------------------------------------
507 int VPiecePath::indexOfNode(quint32 id) const
508 {
509  return indexOfNode(d->m_nodes, id);
510 }
511 
512 //---------------------------------------------------------------------------------------------------------------------
513 /**
514  * @brief NodeOnEdge return nodes located on edge with index.
515  * @param index index of edge.
516  * @param p1 first node.
517  * @param p2 second node.
518  */
519 void VPiecePath::NodeOnEdge(quint32 index, VPieceNode &p1, VPieceNode &p2) const
520 {
521  const QVector<VPieceNode> list = ListNodePoint();
522  if (index > static_cast<quint32>(list.size()))
523  {
524  qDebug()<<"Wrong edge index index ="<<index;
525  return;
526  }
527  p1 = list.at(static_cast<int>(index));
528  if (index + 1 > static_cast<quint32>(list.size()) - 1)
529  {
530  p2 = list.at(0);
531  }
532  else
533  {
534  p2 = list.at(static_cast<int>(index+1));
535  }
536 }
537 
538 //---------------------------------------------------------------------------------------------------------------------
539 bool VPiecePath::Contains(quint32 id) const
540 {
541  for (int i = 0; i < d->m_nodes.size(); ++i)
542  {
543  if (d->m_nodes.at(i).GetId() == id)
544  {
545  return true;
546  }
547  }
548  return false;
549 }
550 
551 //---------------------------------------------------------------------------------------------------------------------
552 /**
553  * @brief OnEdge checks if two poins located on the edge. Edge is line between two points. If between two points
554  * located arcs or splines ignore this.
555  * @param p1 id first point.
556  * @param p2 id second point.
557  * @return true - on edge, false - no.
558  */
559 bool VPiecePath::OnEdge(quint32 p1, quint32 p2) const
560 {
561  const QVector<VPieceNode> list = ListNodePoint();
562  if (list.size() < 2)
563  {
564  qDebug()<<"Not enough points.";
565  return false;
566  }
567  int i = IndexOfNode(list, p1);
568  int j1 = 0, j2 = 0;
569 
570  if (i == list.size() - 1)
571  {
572  j1 = i-1;
573  j2 = 0;
574  }
575  else if (i == 0)
576  {
577  j1 = list.size() - 1;
578  j2 = i + 1;
579  }
580  else
581  {
582  j1 = i - 1;
583  j2 = i + 1;
584  }
585 
586  if (list.at(j1).GetId() == p2 || list.at(j2).GetId() == p2)
587  {
588  return true;
589  }
590  else
591  {
592  return false;
593  }
594 }
595 
596 //---------------------------------------------------------------------------------------------------------------------
597 /**
598  * @brief Edge return edge index in detail. Edge is line between two points. If between two points
599  * located arcs or splines ignore this.
600  * @param p1 id first point.
601  * @param p2 id second point.
602  * @return edge index or -1 if points don't located on edge
603  */
604 int VPiecePath::Edge(quint32 p1, quint32 p2) const
605 {
606  if (OnEdge(p1, p2) == false)
607  {
608  qDebug()<<"Points don't on edge.";
609  return -1;
610  }
611 
612  const QVector<VPieceNode> list = ListNodePoint();
613  int i = IndexOfNode(list, p1);
614  int j = IndexOfNode(list, p2);
615 
616  int min = qMin(i, j);
617 
618  if (min == 0 && (i == list.size() - 1 || j == list.size() - 1))
619  {
620  return list.size() - 1;
621  }
622  else
623  {
624  return min;
625  }
626 }
627 
628 //---------------------------------------------------------------------------------------------------------------------
629 /**
630  * @brief listNodePoint return list nodes only with points.
631  * @return list points node.
632  */
634 {
635  QVector<VPieceNode> list;
636  for (int i = 0; i < d->m_nodes.size(); ++i) //-V807
637  {
638  if (d->m_nodes.at(i).GetTypeTool() == Tool::NodePoint)
639  {
640  list.append(d->m_nodes.at(i));
641  }
642  }
643  return list;
644 }
645 
646 //---------------------------------------------------------------------------------------------------------------------
647 /**
648  * @brief RemoveEdge return path without edge with index.
649  * @param index idex of edge.
650  * @return path without edge with index.
651  */
652 VPiecePath VPiecePath::RemoveEdge(quint32 index) const
653 {
654  VPiecePath path(*this);
655  path.Clear();
656 
657  // Edge can be only segment. We ignore all curves inside segments.
658  const quint32 edges = static_cast<quint32>(ListNodePoint().size());
659  quint32 k = 0;
660  for (quint32 i=0; i<edges; ++i)
661  {
662  if (i == index)
663  {
664  path.Append(this->at(static_cast<int>(k)));
665  ++k;
666  }
667  else
668  {
669  VPieceNode p1;
670  VPieceNode p2;
671  this->NodeOnEdge(i, p1, p2);
672  const int j1 = this->indexOfNode(p1.GetId());
673  int j2 = this->indexOfNode(p2.GetId());
674  if (j2 == 0)
675  {
676  j2 = this->CountNodes();
677  }
678  for (int j=j1; j<j2; ++j)
679  {// Add "segment" except last point. Inside can be curves too.
680  path.Append(this->at(j));
681  ++k;
682  }
683  }
684  }
685  return path;
686 }
687 
688 //---------------------------------------------------------------------------------------------------------------------
689 VSAPoint VPiecePath::StartSegment(const VContainer *data, int i, bool reverse) const
690 {
691  return StartSegment(data, d->m_nodes, i, reverse);
692 }
693 
694 //---------------------------------------------------------------------------------------------------------------------
695 VSAPoint VPiecePath::EndSegment(const VContainer *data, int i, bool reverse) const
696 {
697  return EndSegment(data, d->m_nodes, i, reverse);
698 }
699 
700 //---------------------------------------------------------------------------------------------------------------------
701 QPointF VPiecePath::NodePreviousPoint(const VContainer *data, int i) const
702 {
703  if (i < 0 || i > d->m_nodes.size()-1)
704  {
705  return QPointF();
706  }
707 
708  if (d->m_nodes.size() > 1)
709  {
710  int index = 0;
711  if (i == 0)
712  {
713  index = d->m_nodes.size()-1;
714  }
715  else
716  {
717  index = i-1;
718  }
719 
720  const VPieceNode &node = d->m_nodes.at(index);
721  switch (node.GetTypeTool())
722  {
723  case (Tool::NodePoint):
724  return static_cast<QPointF>(*data->GeometricObject<VPointF>(node.GetId()));
725  case (Tool::NodeArc):
726  case (Tool::NodeElArc):
727  case (Tool::NodeSpline):
728  case (Tool::NodeSplinePath):
729  {
731 
732  const VSAPoint begin = StartSegment(data, d->m_nodes, index, node.GetReverse());
733  const VSAPoint end = EndSegment(data, d->m_nodes, index, node.GetReverse());
734 
735  const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, node.GetReverse());
736  if (points.size() > 1)
737  {
738  return points.at(points.size()-2);
739  }
740  }
741  break;
742  default:
743  qDebug() << "Got wrong tool type. Ignore." << static_cast<char>(node.GetTypeTool());
744  break;
745  }
746  }
747 
748  return QPointF();
749 }
750 
751 //---------------------------------------------------------------------------------------------------------------------
752 QPointF VPiecePath::NodeNextPoint(const VContainer *data, int i) const
753 {
754  QPointF point;
755  if (i < 0 || i > d->m_nodes.size()-1)
756  {
757  return point;
758  }
759 
760  if (d->m_nodes.size() > 1)
761  {
762  int index = 0;
763  if (i == d->m_nodes.size() - 1)
764  {
765  index = 0;
766  }
767  else
768  {
769  index = i+1;
770  }
771 
772  const VPieceNode &node = d->m_nodes.at(index);
773  switch (node.GetTypeTool())
774  {
775  case (Tool::NodePoint):
776  return static_cast<QPointF>(*data->GeometricObject<VPointF>(node.GetId()));
777  case (Tool::NodeArc):
778  case (Tool::NodeElArc):
779  case (Tool::NodeSpline):
780  case (Tool::NodeSplinePath):
781  {
783 
784  const VSAPoint begin = StartSegment(data, d->m_nodes, index, node.GetReverse());
785  const VSAPoint end = EndSegment(data, d->m_nodes, index, node.GetReverse());
786 
787  const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, node.GetReverse());
788  if (points.size() > 1)
789  {
790  return points.at(1);
791  }
792  }
793  break;
794  default:
795  qDebug()<<"Got wrong tool type. Ignore."<< static_cast<char>(node.GetTypeTool());
796  break;
797  }
798  }
799 
800  return point;
801 }
802 
803 //---------------------------------------------------------------------------------------------------------------------
804 int VPiecePath::indexOfNode(const QVector<VPieceNode> &nodes, quint32 id)
805 {
806  for (int i = 0; i < nodes.size(); ++i)
807  {
808  if (nodes.at(i).GetId() == id)
809  {
810  return i;
811  }
812  }
813  qDebug()<<"Can't find node.";
814  return -1;
815 }
816 
817 //---------------------------------------------------------------------------------------------------------------------
819 {
820  if (start < 0 || start >= nodes.size())
821  {
822  return -1;
823  }
824 
825  int i = (start == 0) ? nodes.size()-1 : start-1;
826 
827  if (i < 0 || i >= nodes.size())
828  {
829  return -1;
830  }
831 
832  int checked = 0;
833  bool found = false;
834  do
835  {
836  if (!nodes.at(i).isExcluded())
837  {
838  found = true;
839  break;
840  }
841 
842  ++checked;
843  --i;
844  if (i < 0)
845  {
846  i = nodes.size() - 1;
847  }
848  } while (checked < nodes.size());
849 
850  return (!found) ? -1 : i;
851 }
852 
853 //---------------------------------------------------------------------------------------------------------------------
855 {
856  if (start < 0 || start >= nodes.size())
857  {
858  return -1;
859  }
860 
861  int i = (start == nodes.size()-1) ? 0 : start+1;
862 
863  if (i < 0 || i >= nodes.size())
864  {
865  return -1;
866  }
867 
868  int checked = 0;
869  bool found = false;
870  do
871  {
872  if (!nodes.at(i).isExcluded())
873  {
874  found = true;
875  break;
876  }
877 
878  ++checked;
879  ++i;
880  if (i >= nodes.size())
881  {
882  i = 0;
883  }
884  } while (checked < nodes.size());
885 
886  return (!found) ? -1 : i;
887 }
888 
889 //---------------------------------------------------------------------------------------------------------------------
891 {
892  SCASSERT(data !=nullptr)
893 
894  const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(node.GetId());
895  VSAPoint p(point->toQPointF());
896 
897  p.SetSAAfter(node.GetSAAfter(data, *data->GetPatternUnit()));
898  p.SetSABefore(node.GetSABefore(data, *data->GetPatternUnit()));
899  p.SetAngleType(node.GetAngleType());
900 
901  return p;
902 }
903 
904 //---------------------------------------------------------------------------------------------------------------------
906  const QSharedPointer<VAbstractCurve> &curve, int i,
907  bool reverse, qreal width)
908 {
909  QVector<VSAPoint> pointsEkv;
910 
911  const VSAPoint begin = StartSegment(data, nodes, i, reverse);
912  const VSAPoint end = EndSegment(data, nodes, i, reverse);
913 
914  const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, reverse);
915  if (points.isEmpty())
916  {
917  return pointsEkv;
918  }
919 
920  qreal w1 = begin.GetSAAfter();
921  qreal w2 = end.GetSABefore();
922  if (w1 < 0 && w2 < 0)
923  {// no local widths
924  for(int i = 0; i < points.size(); ++i)
925  {
926  VSAPoint p(points.at(i));
927  if (i == 0)
928  { // first point
929  p.SetSAAfter(begin.GetSAAfter());
930  p.SetSABefore(begin.GetSABefore());
931  p.SetAngleType(begin.GetAngleType());
932  }
933  else if (i == points.size() - 1)
934  { // last point
935  p.SetSAAfter(end.GetSAAfter());
936  p.SetSABefore(end.GetSABefore());
937  p.SetAngleType(end.GetAngleType());
938  }
939  pointsEkv.append(p);
940  }
941  }
942  else
943  {
944  if (w1 < 0)
945  {
946  w1 = width;
947  }
948 
949  if (w2 < 0)
950  {
951  w2 = width;
952  }
953 
954  const qreal wDiff = w2 - w1;// Difference between to local widths
955  const qreal fullLength = VAbstractCurve::PathLength(points);
956 
957  VSAPoint p(points.at(0));//First point in the list
958  p.SetSAAfter(begin.GetSAAfter());
959  p.SetSABefore(begin.GetSABefore());
960  p.SetAngleType(begin.GetAngleType());
961  pointsEkv.append(p);
962 
963  qreal length = 0; // how much we handle
964 
965  for(int i = 1; i < points.size(); ++i)
966  {
967  p = VSAPoint(points.at(i));
968 
969  if (i == points.size() - 1)
970  {// last point
971  p.SetSAAfter(end.GetSAAfter());
972  p.SetSABefore(end.GetSABefore());
973  p.SetAngleType(end.GetAngleType());
974  }
975  else
976  {
977  length += QLineF(points.at(i-1), points.at(i)).length();
978  const qreal localWidth = w1 + wDiff*(length/fullLength);
979 
980  p.SetSAAfter(localWidth);
981  p.SetSABefore(localWidth);
982  // curve points have angle type by default
983  }
984 
985  pointsEkv.append(p);
986  }
987  }
988 
989  return pointsEkv;
990 }
static qreal PathLength(const QVector< QPointF > &path)
static bool isPointOnCurve(const QVector< QPointF > &points, const QPointF &p)
The VContainer class container of all variables.
Definition: vcontainer.h:141
const QSharedPointer< T > GeometricObject(const quint32 &id) const
Definition: vcontainer.h:266
const Unit * GetPatternUnit() const
Definition: vcontainer.cpp:599
static QVector< T > GetReversePoints(const QVector< T > &points)
GetReversePoint return revers container of points.
Definition: vgobject.h:145
qreal GetSABefore(const VContainer *data) const
Definition: vpiecenode.cpp:188
Tool GetTypeTool() const
Definition: vpiecenode.cpp:161
quint32 GetId() const
Definition: vpiecenode.cpp:149
bool isExcluded() const
Definition: vpiecenode.cpp:411
PieceNodeAngle GetAngleType() const
Definition: vpiecenode.cpp:272
bool GetReverse() const
Definition: vpiecenode.cpp:173
qreal GetSAAfter(const VContainer *data) const
Definition: vpiecenode.cpp:230
QVector< QPointF > PathPoints(const VContainer *data) const
Definition: vpiecepath.cpp:287
PiecePathType GetType() const
Definition: vpiecepath.cpp:239
bool Contains(quint32 id) const
Definition: vpiecepath.cpp:539
void SetType(PiecePathType type)
Definition: vpiecepath.cpp:245
QVector< VSAPoint > SeamAllowancePoints(const VContainer *data, qreal width, bool reverse) const
Definition: vpiecepath.cpp:357
qint32 CountNodes() const
Definition: vpiecepath.cpp:209
void NodeOnEdge(quint32 index, VPieceNode &p1, VPieceNode &p2) const
NodeOnEdge return nodes located on edge with index.
Definition: vpiecepath.cpp:519
QSharedDataPointer< VPiecePathData > d
Definition: vpiecepath.h:146
VPiecePath & operator=(const VPiecePath &path)
Definition: vpiecepath.cpp:182
void Clear()
Definition: vpiecepath.cpp:203
void SetCutPath(bool cut)
Definition: vpiecepath.cpp:281
static QVector< VSAPoint > CurveSeamAllowanceSegment(const VContainer *data, const QVector< VPieceNode > &nodes, const QSharedPointer< VAbstractCurve > &curve, int i, bool reverse, qreal width)
Definition: vpiecepath.cpp:905
void Append(const VPieceNode &node)
Definition: vpiecepath.cpp:197
void Swap(VPiecePath &path) Q_DECL_NOTHROW
Definition: vpiecepath.cpp:163
static int FindInLoopNotExcludedUp(int start, const QVector< VPieceNode > &nodes)
Definition: vpiecepath.cpp:818
int Edge(quint32 p1, quint32 p2) const
Edge return edge index in detail. Edge is line between two points. If between two points located arcs...
Definition: vpiecepath.cpp:604
VPieceNode & operator[](int indx)
Definition: vpiecepath.cpp:215
QVector< VPointF > PathNodePoints(const VContainer *data, bool showExcluded=true) const
Definition: vpiecepath.cpp:328
QVector< VPieceNode > GetNodes() const
Definition: vpiecepath.cpp:227
VPiecePath RemoveEdge(quint32 index) const
RemoveEdge return path without edge with index.
Definition: vpiecepath.cpp:652
QVector< quint32 > MissingNodes(const VPiecePath &path) const
Definition: vpiecepath.cpp:473
void SetNodes(const QVector< VPieceNode > &nodes)
Definition: vpiecepath.cpp:233
void SetPenType(const Qt::PenStyle &type)
Definition: vpiecepath.cpp:269
void SetName(const QString &name)
Definition: vpiecepath.cpp:257
QPointF NodePreviousPoint(const VContainer *data, int i) const
Definition: vpiecepath.cpp:701
bool OnEdge(quint32 p1, quint32 p2) const
OnEdge checks if two poins located on the edge. Edge is line between two points. If between two point...
Definition: vpiecepath.cpp:559
QPointF NodeNextPoint(const VContainer *data, int i) const
Definition: vpiecepath.cpp:752
Qt::PenStyle GetPenType() const
Definition: vpiecepath.cpp:263
const VPieceNode & at(int indx) const
Definition: vpiecepath.cpp:221
static VSAPoint PreparePointEkv(const VPieceNode &node, const VContainer *data)
Definition: vpiecepath.cpp:890
static int FindInLoopNotExcludedDown(int start, const QVector< VPieceNode > &nodes)
Definition: vpiecepath.cpp:854
bool IsCutPath() const
Definition: vpiecepath.cpp:275
QVector< VPieceNode > ListNodePoint() const
listNodePoint return list nodes only with points.
Definition: vpiecepath.cpp:633
VSAPoint StartSegment(const VContainer *data, int i, bool reverse) const
Definition: vpiecepath.cpp:689
int indexOfNode(quint32 id) const
Definition: vpiecepath.cpp:507
VSAPoint EndSegment(const VContainer *data, int i, bool reverse) const
Definition: vpiecepath.cpp:695
QPainterPath PainterPath(const VContainer *data) const
Definition: vpiecepath.cpp:396
QString GetName() const
Definition: vpiecepath.cpp:251
The VPointF class keep data of point.
Definition: vpointf.h:75
The VSAPoint class seam allowance point.
void SetAngleType(PieceNodeAngle value)
Q_DECL_CONSTEXPR PieceNodeAngle GetAngleType() const
Q_DECL_CONSTEXPR qreal GetSABefore() const
void SetSABefore(qreal value)
Q_DECL_CONSTEXPR qreal GetSAAfter() const
void SetSAAfter(qreal value)
#define SCASSERT(cond)
Definition: def.h:317
PiecePathType
Definition: def.h:157
@ NodeSplinePath
@ NodeSpline
@ NodeElArc
@ NodeArc
@ NodePoint
VSAPoint CurvePoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node, const QVector< QPointF > &curvePoints)
Definition: vpiecepath.cpp:64
int IndexOfNode(const QVector< VPieceNode > &list, quint32 id)
indexOfNode return index in list node using id object.
Definition: vpiecepath.cpp:142
VSAPoint CurveEndPoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node, const QVector< QPointF > &curvePoints)
Definition: vpiecepath.cpp:109
VSAPoint CurveStartPoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node, const QVector< QPointF > &curvePoints)
Definition: vpiecepath.cpp:82