Seamly2D
Code documentation
vistoolcubicbezierpath.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 vistoolcubicbezierpath.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date 18 3, 2016
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) 2016 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 "vistoolcubicbezierpath.h"
53 
54 #include <QGraphicsLineItem>
55 #include <QGraphicsPathItem>
56 #include <QLineF>
57 #include <QPainterPath>
58 #include <QPointF>
59 #include <Qt>
60 #include <QtAlgorithms>
61 
62 #include "../vgeometry/vabstractcurve.h"
63 #include "../vgeometry/vpointf.h"
64 #include "../vgeometry/vspline.h"
65 #include "../visualization.h"
66 #include "vispath.h"
67 #include "../vwidgets/scalesceneitems.h"
68 
69 //---------------------------------------------------------------------------------------------------------------------
71  : VisPath(data, parent),
72  mainPoints(),
73  ctrlPoints(),
74  lines(),
75  newCurveSegment(nullptr),
76  path(),
77  helpLine1(nullptr),
78  helpLine2(nullptr)
79 {
80  helpLine1 = InitItem<VScaledLine>(mainColor, this);
81  helpLine2 = InitItem<VScaledLine>(mainColor, this);
82 
83  newCurveSegment = InitItem<VCurvePathItem>(mainColor, this);
84 }
85 
86 //---------------------------------------------------------------------------------------------------------------------
88 {
89  qDeleteAll(mainPoints);
90  qDeleteAll(lines);
91 }
92 
93 //---------------------------------------------------------------------------------------------------------------------
95 {
96  const QVector<VPointF> pathPoints = path.GetCubicPath();
97  const int size = pathPoints.size();
98  if (size > 0)
99  {
100  const int countSubSpl = VCubicBezierPath::CountSubSpl(size);
101 
102  for (int i = 0; i < size; ++i)
103  {
104  VScaledEllipse *point = this->getPoint(mainPoints, static_cast<unsigned>(i), 1/*zValue*/);
105  DrawPoint(point, static_cast<QPointF>(pathPoints.at(i)), supportColor);
106  }
107 
108  if (mode == Mode::Creation)
109  {
110  if (countSubSpl < 1)
111  {
112  Creating(pathPoints, size-1);
113  }
114  else
115  {
116  const qint32 last = VCubicBezierPath::SubSplOffset(countSubSpl) + 3;
117  Creating(pathPoints, size-1-last);
118  }
119  }
120 
121  if (countSubSpl >= 1)
122  {
123  DrawPath(this, path.GetPath(), path.DirectionArrows(), mainColor, lineStyle, lineWeight, Qt::RoundCap);
124 
125  for (qint32 i = 1; i<=countSubSpl; ++i)
126  {
127  const int preLastPoint = (countSubSpl - 1) * 2;
128  const int lastPoint = preLastPoint + 1;
129 
130  const VSpline spl = path.GetSpline(i);
131 
132  VScaledLine *ctrlLine1 = this->getLine(static_cast<unsigned>(preLastPoint));
133  DrawLine(ctrlLine1, QLineF(static_cast<QPointF>(spl.GetP1()), static_cast<QPointF>(spl.GetP2())),
134  mainColor, lineWeight, Qt::DashLine);
135 
136  VScaledEllipse *p2 = this->getPoint(ctrlPoints, static_cast<unsigned>(preLastPoint));
137  DrawPoint(p2, static_cast<QPointF>(spl.GetP2()), Qt::green);
138 
139  VScaledLine *ctrlLine2 = this->getLine(static_cast<unsigned>(lastPoint));
140  DrawLine(ctrlLine2, QLineF(static_cast<QPointF>(spl.GetP4()), static_cast<QPointF>(spl.GetP3())),
141  mainColor, lineWeight, Qt::DashLine);
142 
143  VScaledEllipse *p3 = this->getPoint(ctrlPoints, static_cast<unsigned>(lastPoint));
144  DrawPoint(p3, static_cast<QPointF>(spl.GetP3()), Qt::green);
145  }
146  }
147 
148  RefreshToolTip();
149  }
150 }
151 
152 //---------------------------------------------------------------------------------------------------------------------
154 {
155  path = value;
156 
157  RefreshToolTip();
158 }
159 
160 //---------------------------------------------------------------------------------------------------------------------
161 // cppcheck-suppress unusedFunction
163 {
164  return path;
165 }
166 
167 //---------------------------------------------------------------------------------------------------------------------
169 {
170  if (not points.isEmpty() && static_cast<quint32>(points.size() - 1) >= i)
171  {
172  return points.at(static_cast<int>(i));
173  }
174  else
175  {
176  auto point = InitPoint(supportColor, this, z);
177  points.append(point);
178  return point;
179  }
180 }
181 
182 //---------------------------------------------------------------------------------------------------------------------
184 {
185  if (static_cast<quint32>(lines.size() - 1) >= i && lines.isEmpty() == false)
186  {
187  return lines.at(static_cast<int>(i));
188  }
189  else
190  {
191  auto line = InitItem<VScaledLine>(mainColor, this);
192  lines.append(line);
193  return line;
194  }
195  return nullptr;
196 }
197 
198 //---------------------------------------------------------------------------------------------------------------------
199 void VisToolCubicBezierPath::Creating(const QVector<VPointF> &pathPoints, int pointsLeft)
200 {
201  const int size = pathPoints.size();
202  if (pathPoints.isEmpty() || size+1 < pointsLeft)
203  {
204  return;
205  }
206 
207  int subSplPoints = 0;
208  const int subSplCount = VCubicBezierPath::CountSubSpl(size);
209  if (subSplCount >= 1)
210  {
211  subSplPoints = VCubicBezierPath::SubSplPointsCount(subSplCount)-1;
212  }
213 
214  switch(pointsLeft)
215  {
216  case 0:
217  {
218  const VPointF p1 = pathPoints.last();
219  if (pathPoints.size() >= 4)
220  {
221  QLineF p1p2(static_cast<QPointF>(p1), Visualization::scenePos);
222  QLineF prP3p1(static_cast<QPointF>(pathPoints.at(size-2)), static_cast<QPointF>(p1));
223  p1p2.setAngle(prP3p1.angle());
224 
225  const QPointF p2 = p1p2.p2();
226 
228  DrawPath(newCurveSegment, spline.GetPath(), mainColor, Qt::SolidLine, lineWeight, Qt::RoundCap);
229 
230  DrawLine(helpLine1, p1p2, mainColor, lineWeight, Qt::DashLine);
231 
232  const int preLastPoint = subSplCount * 2;
233  VScaledEllipse *p2Ctrl = this->getPoint(ctrlPoints, static_cast<unsigned>(preLastPoint));
234  DrawPoint(p2Ctrl, p2, Qt::green);
235  }
236  else
237  {
238  DrawLine(helpLine1, QLineF(static_cast<QPointF>(p1), Visualization::scenePos), mainColor,
239  lineWeight, Qt::DashLine);
240  }
241  break;
242  }
243  case 1:
244  {
245  const VPointF p1 = pathPoints.at(subSplPoints + pointsLeft-1);
246  QPointF p2 = static_cast<QPointF>(pathPoints.at(subSplPoints + pointsLeft));
247 
248  if (subSplCount >= 1)
249  {
250  QLineF p1p2(static_cast<QPointF>(p1), p2);
251  QLineF prP3p1(static_cast<QPointF>(pathPoints.at(subSplPoints + pointsLeft-2)),
252  static_cast<QPointF>(p1));
253  p1p2.setAngle(prP3p1.angle());
254  p2 = p1p2.p2();
255  }
256 
257  DrawLine(helpLine1, QLineF(static_cast<QPointF>(p1), p2), mainColor, lineWeight, Qt::DashLine);
258 
260  DrawPath(newCurveSegment, spline.GetPath(), mainColor, Qt::SolidLine, lineWeight, Qt::RoundCap);
261 
262  const int preLastPoint = subSplCount * 2;
263  VScaledEllipse *p2Ctrl = this->getPoint(ctrlPoints, static_cast<unsigned>(preLastPoint));
264  DrawPoint(p2Ctrl, p2, Qt::green);
265  break;
266  }
267  case 2:
268  {
269  const VPointF p1 = pathPoints.at(subSplPoints + pointsLeft-2);
270  QPointF p2 = static_cast<QPointF>(pathPoints.at(subSplPoints + pointsLeft-1));
271  const QPointF p3 = static_cast<QPointF>(pathPoints.at(subSplPoints + pointsLeft));
272 
273  if (subSplCount >= 1)
274  {
275  QLineF p1p2(static_cast<QPointF>(p1), p2);
276  QLineF prP3p1(static_cast<QPointF>(pathPoints.at(subSplPoints + pointsLeft-3)),
277  static_cast<QPointF>(p1));
278  p1p2.setAngle(prP3p1.angle());
279  p2 = p1p2.p2();
280  }
281 
282  DrawLine(helpLine1, QLineF(static_cast<QPointF>(p1), p2), mainColor, lineWeight, Qt::DashLine);
283  DrawLine(helpLine2, QLineF(p3, Visualization::scenePos), mainColor, lineWeight, Qt::DashLine);
284 
285  VSpline spline(p1, p2, p3, VPointF(Visualization::scenePos));
286  DrawPath(newCurveSegment, spline.GetPath(), mainColor, Qt::SolidLine, lineWeight, Qt::RoundCap);
287 
288  const int preLastPoint = subSplCount * 2;
289  VScaledEllipse *p2Ctrl = this->getPoint(ctrlPoints, static_cast<unsigned>(preLastPoint));
290  DrawPoint(p2Ctrl, p2, Qt::green);
291  break;
292  }
293  default:
294  break;
295  }
296 }
297 
298 //---------------------------------------------------------------------------------------------------------------------
300 {
301  const int size = path.CountPoints();
302  if (size > 0)
303  {
304  const int countSubSpl = VCubicBezierPath::CountSubSpl(size);
305 
306  if (size < 7)
307  {
308  Visualization::toolTip = tr("<b>Curved path</b>: select seven or more points");
309  }
310  else if (size - VCubicBezierPath::SubSplPointsCount(countSubSpl) == 0)
311  {
312  Visualization::toolTip = tr("<b>Curved path</b>: select seven or more points, "
313  "Press <b>ENTER</b> to finish tool creation");
314  }
315  else
316  {
317  Visualization::toolTip = tr("<b>Curved path</b>: select more points for complete segment");
318  }
319 
320  if (mode == Mode::Show)
321  {
323  }
325  }
326 }
virtual QPainterPath GetPath() const Q_DECL_OVERRIDE
GetPath return QPainterPath which reprezent spline path.
virtual QVector< DirectionArrow > DirectionArrows() const Q_DECL_OVERRIDE
virtual QPainterPath GetPath() const
The VContainer class container of all variables.
Definition: vcontainer.h:141
static qint32 SubSplPointsCount(qint32 countSubSpl)
QVector< VPointF > GetCubicPath() const
virtual qint32 CountPoints() const Q_DECL_OVERRIDE
virtual qint32 CountSubSpl() const Q_DECL_OVERRIDE
virtual VSpline GetSpline(qint32 index) const Q_DECL_OVERRIDE
static qint32 SubSplOffset(qint32 subSplIndex)
The VPointF class keep data of point.
Definition: vpointf.h:75
VSpline class that implements the spline.
Definition: vspline.h:75
virtual VPointF GetP4() const Q_DECL_OVERRIDE
GetP4 return last spline point.
Definition: vspline.cpp:321
virtual VPointF GetP1() const Q_DECL_OVERRIDE
GetP1 return first spline point.
Definition: vspline.cpp:281
virtual VPointF GetP2() const Q_DECL_OVERRIDE
GetP2 return first control point.
Definition: vspline.cpp:297
virtual VPointF GetP3() const Q_DECL_OVERRIDE
GetP3 return second control point.
Definition: vspline.cpp:309
void Creating(const QVector< VPointF > &pathPoints, int pointsLeft)
VCurvePathItem * newCurveSegment
VScaledEllipse * getPoint(QVector< VScaledEllipse * > &points, quint32 i, qreal z=0)
QVector< VScaledEllipse * > mainPoints
virtual void RefreshGeometry() Q_DECL_OVERRIDE
VisToolCubicBezierPath(const VContainer *data, QGraphicsItem *parent=nullptr)
void setPath(const VCubicBezierPath &value)
VScaledLine * getLine(quint32 i)
QVector< VScaledEllipse * > ctrlPoints
QVector< VScaledLine * > lines
QColor supportColor
void ToolTip(const QString &toolTip)
QColor mainColor
Definition: visualization.h:99
void DrawPoint(QGraphicsEllipseItem *point, const QPointF &pos, const QColor &color, Qt::PenStyle style=Qt::SolidLine)
void DrawPath(VCurvePathItem *pathItem, const QPainterPath &path, const QColor &color, Qt::PenStyle style=Qt::SolidLine, const qreal &weight=0.35, Qt::PenCapStyle cap=Qt::SquareCap)
QPointF scenePos
Definition: visualization.h:98
virtual void DrawLine(VScaledLine *lineItem, const QLineF &line, const QColor &color, const qreal &lineWeight, Qt::PenStyle style=Qt::SolidLine)
VScaledEllipse * InitPoint(const QColor &color, QGraphicsItem *parent, qreal z=0) const
Qt::PenStyle lineStyle
@ Creation