1 /************************************************************************
2 **
3 ** @file vsplinepath.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date November 15, 2013
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 "vsplinepath.h"
30
31 #include <QJsonArray>
32 #include <QJsonObject>
33 #include <QPoint>
34
35 #include "../ifc/exception/vexception.h"
36 #include "../vmisc/vmath.h"
37 #include "../vmisc/compatibility.h"
38 #include "vabstractcurve.h"
39 #include "vsplinepath_p.h"
40
41 //---------------------------------------------------------------------------------------------------------------------
42 /**
43 * @brief VSplinePath constructor.
44 * @param idObject parent id.
45 * @param mode mode creation spline path.
46 */
VSplinePath(quint32 idObject,Draw mode)47 VSplinePath::VSplinePath(quint32 idObject, Draw mode)
48 : VAbstractCubicBezierPath(GOType::SplinePath, idObject, mode),
49 d(new VSplinePathData())
50 {}
51
52 //---------------------------------------------------------------------------------------------------------------------
VSplinePath(const QVector<VFSplinePoint> & points,qreal kCurve,quint32 idObject,Draw mode)53 VSplinePath::VSplinePath(const QVector<VFSplinePoint> &points, qreal kCurve, quint32 idObject, Draw mode)
54 : VAbstractCubicBezierPath(GOType::SplinePath, idObject, mode),
55 d(new VSplinePathData())
56 {
57 if (points.size() < 3)
58 {
59 return;
60 }
61
62 QVector<VSplinePoint> newPoints(points.size());
63 for (qint32 i = 1; i <= points.size()-1; ++i)
64 {
65 const VFSplinePoint &p1 = points.at(i-1);
66 const VFSplinePoint &p2 = points.at(i);
67 VSpline spl(p1.P(), p2.P(), p1.Angle2(), p2.Angle1(), p1.KAsm2(), p2.KAsm1(), kCurve);
68
69 newPoints[i-1].SetP(p1.P());
70 newPoints[i-1].SetAngle2(p1.Angle2(), spl.GetStartAngleFormula());
71 newPoints[i-1].SetLength2(spl.GetC1Length(), spl.GetC1LengthFormula());
72
73 newPoints[i].SetP(p2.P());
74 newPoints[i].SetAngle1(p2.Angle1(), spl.GetEndAngleFormula());
75 newPoints[i].SetLength1(spl.GetC2Length(), spl.GetC2LengthFormula());
76 }
77
78 d->path = newPoints;
79 CreateName();
80 }
81
82 //---------------------------------------------------------------------------------------------------------------------
VSplinePath(const QVector<VSplinePoint> & points,quint32 idObject,Draw mode)83 VSplinePath::VSplinePath(const QVector<VSplinePoint> &points, quint32 idObject, Draw mode)
84 : VAbstractCubicBezierPath(GOType::SplinePath, idObject, mode),
85 d(new VSplinePathData())
86 {
87 if (points.isEmpty())
88 {
89 return;
90 }
91
92 d->path = points;
93 CreateName();
94 }
95
96 //---------------------------------------------------------------------------------------------------------------------
97 /**
98 * @brief VSplinePath copy constructor.
99 * @param splPath spline path.
100 */
VSplinePath(const VSplinePath & splPath)101 VSplinePath::VSplinePath(const VSplinePath &splPath)
102 : VAbstractCubicBezierPath(splPath),
103 d(splPath.d)
104 {}
105
106 //---------------------------------------------------------------------------------------------------------------------
Rotate(const QPointF & originPoint,qreal degrees,const QString & prefix) const107 VSplinePath VSplinePath::Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix) const
108 {
109 QVector<VSplinePoint> newPoints(CountPoints());
110 for (qint32 i = 1; i <= CountSubSpl(); ++i)
111 {
112 const VSpline spl = GetSpline(i).Rotate(originPoint, degrees);
113
114 newPoints[i-1].SetP(spl.GetP1());
115 newPoints[i-1].SetAngle2(spl.GetStartAngle(), spl.GetStartAngleFormula());
116 newPoints[i-1].SetLength2(spl.GetC1Length(), spl.GetC1LengthFormula());
117
118 newPoints[i].SetP(spl.GetP4());
119 newPoints[i].SetAngle1(spl.GetEndAngle(), spl.GetEndAngleFormula());
120 newPoints[i].SetLength1(spl.GetC2Length(), spl.GetC2LengthFormula());
121 }
122
123 VSplinePath splPath(newPoints);
124 splPath.setName(name() + prefix);
125
126 if (not GetAliasSuffix().isEmpty())
127 {
128 splPath.SetAliasSuffix(GetAliasSuffix() + prefix);
129 }
130
131 splPath.SetColor(GetColor());
132 splPath.SetPenStyle(GetPenStyle());
133 splPath.SetApproximationScale(GetApproximationScale());
134 return splPath;
135 }
136
137 //---------------------------------------------------------------------------------------------------------------------
Flip(const QLineF & axis,const QString & prefix) const138 VSplinePath VSplinePath::Flip(const QLineF &axis, const QString &prefix) const
139 {
140 QVector<VSplinePoint> newPoints(CountPoints());
141 for (qint32 i = 1; i <= CountSubSpl(); ++i)
142 {
143 const VSpline spl = GetSpline(i).Flip(axis);
144
145 newPoints[i-1].SetP(spl.GetP1());
146 newPoints[i-1].SetAngle2(spl.GetStartAngle(), spl.GetStartAngleFormula());
147 newPoints[i-1].SetLength2(spl.GetC1Length(), spl.GetC1LengthFormula());
148
149 newPoints[i].SetP(spl.GetP4());
150 newPoints[i].SetAngle1(spl.GetEndAngle(), spl.GetEndAngleFormula());
151 newPoints[i].SetLength1(spl.GetC2Length(), spl.GetC2LengthFormula());
152 }
153
154 VSplinePath splPath(newPoints);
155 splPath.setName(name() + prefix);
156
157 if (not GetAliasSuffix().isEmpty())
158 {
159 splPath.SetAliasSuffix(GetAliasSuffix() + prefix);
160 }
161
162 splPath.SetColor(GetColor());
163 splPath.SetPenStyle(GetPenStyle());
164 splPath.SetApproximationScale(GetApproximationScale());
165 return splPath;
166 }
167
168 //---------------------------------------------------------------------------------------------------------------------
Move(qreal length,qreal angle,const QString & prefix) const169 VSplinePath VSplinePath::Move(qreal length, qreal angle, const QString &prefix) const
170 {
171 QVector<VSplinePoint> newPoints(CountPoints());
172 for (qint32 i = 1; i <= CountSubSpl(); ++i)
173 {
174 const VSpline spl = GetSpline(i).Move(length, angle);
175
176 newPoints[i-1].SetP(spl.GetP1());
177 newPoints[i-1].SetAngle2(spl.GetStartAngle(), spl.GetStartAngleFormula());
178 newPoints[i-1].SetLength2(spl.GetC1Length(), spl.GetC1LengthFormula());
179
180 newPoints[i].SetP(spl.GetP4());
181 newPoints[i].SetAngle1(spl.GetEndAngle(), spl.GetEndAngleFormula());
182 newPoints[i].SetLength1(spl.GetC2Length(), spl.GetC2LengthFormula());
183 }
184
185 VSplinePath splPath(newPoints);
186 splPath.setName(name() + prefix);
187
188 if (not GetAliasSuffix().isEmpty())
189 {
190 splPath.SetAliasSuffix(GetAliasSuffix() + prefix);
191 }
192
193 splPath.SetColor(GetColor());
194 splPath.SetPenStyle(GetPenStyle());
195 splPath.SetApproximationScale(GetApproximationScale());
196 return splPath;
197 }
198
199 //---------------------------------------------------------------------------------------------------------------------
~VSplinePath()200 VSplinePath::~VSplinePath()
201 {}
202
203 //---------------------------------------------------------------------------------------------------------------------
204 /**
205 * @brief append add point in the end of list points.
206 * @param point new point.
207 */
append(const VSplinePoint & point)208 void VSplinePath::append(const VSplinePoint &point)
209 {
210 if (d->path.size() > 0 && static_cast<QPointF>(d->path.last().P()) == static_cast<QPointF>(point.P())) //-V807
211 {
212 return;
213 }
214
215 d->path.append(point);
216 CreateName();
217 }
218
219 //---------------------------------------------------------------------------------------------------------------------
220 /**
221 * @brief CountSubSpl return count of simple splines.
222 * @return count.
223 */
CountSubSpl() const224 qint32 VSplinePath::CountSubSpl() const
225 {
226 if (d->path.isEmpty())
227 {
228 return 0;
229 }
230 else
231 {
232 return d->path.size() - 1;
233 }
234 }
235
236 //---------------------------------------------------------------------------------------------------------------------
237 /**
238 * @brief GetSpline return spline by index.
239 * @param index index spline in spline path.
240 * @return spline
241 */
GetSpline(qint32 index) const242 VSpline VSplinePath::GetSpline(qint32 index) const
243 {
244 if (CountPoints()<1)
245 {
246 throw VException(tr("Not enough points to create the spline."));
247 }
248
249 if (index < 1 || index > CountSubSpl())
250 {
251 throw VException(tr("This spline does not exist."));
252 }
253
254 const VSplinePoint &p1 = d->path.at(index-1);
255 const VSplinePoint &p2 = d->path.at(index);
256 VSpline spl(p1.P(), p2.P(), p1.Angle2(), p1.Angle2Formula(), p2.Angle1(), p2.Angle1Formula(), p1.Length2(),
257 p1.Length2Formula(), p2.Length1(), p2.Length1Formula(), 1);
258 spl.SetApproximationScale(GetApproximationScale());
259 return spl;
260 }
261
262 //---------------------------------------------------------------------------------------------------------------------
263 /**
264 * @brief UpdatePoint update spline point in list.
265 * @param indexSpline spline index in list.
266 * @param pos position point in spline.
267 * @param point point.
268 */
UpdatePoint(qint32 indexSpline,const SplinePointPosition & pos,const VSplinePoint & point)269 void VSplinePath::UpdatePoint(qint32 indexSpline, const SplinePointPosition &pos, const VSplinePoint &point)
270 {
271 if (indexSpline < 1 || indexSpline > CountSubSpl())
272 {
273 throw VException(tr("This spline does not exist."));
274 }
275 if (pos == SplinePointPosition::FirstPoint)
276 {
277 d->path[indexSpline-1] = point;
278 }
279 else
280 {
281 d->path[indexSpline] = point;
282 }
283 }
284
285 //---------------------------------------------------------------------------------------------------------------------
286 /**
287 * @brief GetSplinePoint return spline point from list.
288 * @param indexSpline spline index in list.
289 * @param pos position point in spline.
290 * @return spline point.
291 */
GetSplinePoint(qint32 indexSpline,SplinePointPosition pos) const292 VSplinePoint VSplinePath::GetSplinePoint(qint32 indexSpline, SplinePointPosition pos) const
293 {
294 if (indexSpline < 1 || indexSpline > CountSubSpl())
295 {
296 throw VException(tr("This spline does not exist."));
297 }
298 if (pos == SplinePointPosition::FirstPoint)
299 {
300 return d->path.at(indexSpline-1);
301 }
302 else
303 {
304 return d->path.at(indexSpline);
305 }
306 }
307
308 //---------------------------------------------------------------------------------------------------------------------
309 /**
310 * @brief operator = assignment operator.
311 * @param path spline path.
312 * @return spline path.
313 */
operator =(const VSplinePath & path)314 VSplinePath &VSplinePath::operator =(const VSplinePath &path)
315 {
316 if ( &path == this )
317 {
318 return *this;
319 }
320 VAbstractCubicBezierPath::operator=(path);
321 d = path.d;
322 return *this;
323 }
324
325 #ifdef Q_COMPILER_RVALUE_REFS
326 //---------------------------------------------------------------------------------------------------------------------
VSplinePath(const VSplinePath && splPath)327 VSplinePath::VSplinePath(const VSplinePath &&splPath) Q_DECL_NOTHROW
328 : VAbstractCubicBezierPath(splPath),
329 d(splPath.d)
330 {}
331
332 //---------------------------------------------------------------------------------------------------------------------
operator =(VSplinePath && path)333 VSplinePath &VSplinePath::operator=(VSplinePath &&path) Q_DECL_NOTHROW
334 {
335 VAbstractCubicBezierPath::operator=(path);
336 std::swap(d, path.d);
337 return *this;
338 }
339 #endif
340
341 //---------------------------------------------------------------------------------------------------------------------
342 /**
343 * @brief operator [] return spline point by index.
344 * @param indx index in list.
345 * @return spline point.
346 */
operator [](int indx)347 VSplinePoint & VSplinePath::operator[](int indx)
348 {
349 return d->path[indx];
350 }
351
352 //---------------------------------------------------------------------------------------------------------------------
353 /**
354 * @brief at return spline point by index.
355 * @param indx index in list.
356 * @return spline point.
357 */
at(int indx) const358 const VSplinePoint &VSplinePath::at(int indx) const
359 {
360 return d->path[indx];
361 }
362
363 //---------------------------------------------------------------------------------------------------------------------
ToJson() const364 QJsonObject VSplinePath::ToJson() const
365 {
366 QJsonObject object = VAbstractCubicBezierPath::ToJson();
367 object[QLatin1String("aScale")] = GetApproximationScale();
368
369 QJsonArray nodesArray;
370 for (auto &node: d->path)
371 {
372 nodesArray.append(node.ToJson());
373 }
374 object[QLatin1String("nodes")] = nodesArray;
375
376 return object;
377 }
378
379 //---------------------------------------------------------------------------------------------------------------------
GetStartAngle() const380 qreal VSplinePath::GetStartAngle() const
381 {
382 return CountPoints() > 0 ? ConstFirst (GetSplinePath()).Angle2() : 0;
383 }
384
385 //---------------------------------------------------------------------------------------------------------------------
GetEndAngle() const386 qreal VSplinePath::GetEndAngle() const
387 {
388 if (CountPoints() > 0)
389 {
390 return ConstLast(GetSplinePath()).Angle1();
391 }
392 else
393 {
394 return 0;
395 }
396 }
397
398 //---------------------------------------------------------------------------------------------------------------------
GetC1Length() const399 qreal VSplinePath::GetC1Length() const
400 {
401 return CountPoints() > 0 ? ConstFirst (GetSplinePath()).Length2() : 0;
402 }
403
404 //---------------------------------------------------------------------------------------------------------------------
GetC2Length() const405 qreal VSplinePath::GetC2Length() const
406 {
407 return CountPoints() > 0 ? ConstFirst (GetSplinePath()).Length1() : 0;
408 }
409
410 //---------------------------------------------------------------------------------------------------------------------
FirstPoint() const411 VPointF VSplinePath::FirstPoint() const
412 {
413 return not d->path.isEmpty() ? ConstFirst (d->path).P() : VPointF();
414 }
415
416 //---------------------------------------------------------------------------------------------------------------------
LastPoint() const417 VPointF VSplinePath::LastPoint() const
418 {
419 const qint32 count = CountSubSpl();
420 return count >= 1 ? d->path.at(count).P() :// Take last point of the last real spline
421 VPointF();
422 }
423
424 //---------------------------------------------------------------------------------------------------------------------
425 /**
426 * @brief CountPoints return count of points.
427 * @return count.
428 */
CountPoints() const429 qint32 VSplinePath::CountPoints() const
430 {
431 return d->path.size();
432 }
433
434 //---------------------------------------------------------------------------------------------------------------------
435 /**
436 * @brief GetSplinePath return list with spline points.
437 * @return list.
438 */
GetSplinePath() const439 QVector<VSplinePoint> VSplinePath::GetSplinePath() const
440 {
441 return d->path;
442 }
443
444 //---------------------------------------------------------------------------------------------------------------------
GetFSplinePath() const445 QVector<VFSplinePoint> VSplinePath::GetFSplinePath() const
446 {
447 QVector<VFSplinePoint> points;
448 points.reserve(d->path.size());
449
450 for (qint32 i = 1; i <= CountSubSpl(); ++i)
451 {
452 const VSplinePoint &p1 = d->path.at(i-1);
453 const VSplinePoint &p2 = d->path.at(i);
454 VSpline spl(p1.P(), p2.P(), p1.Angle2(), p1.Angle2Formula(), p2.Angle1(), p2.Angle1Formula(), p1.Length2(),
455 p1.Length2Formula(), p2.Length1(), p2.Length1Formula(), 1);
456
457 points[i-1].SetP(p1.P());
458 points[i-1].SetAngle2(p1.Angle2());
459 points[i-1].SetKAsm2(spl.GetKasm1());
460
461 points[i].SetP(p2.P());
462 points[i].SetAngle1(p2.Angle1());
463 points[i].SetKAsm1(spl.GetKasm2());
464 }
465
466 return points;
467 }
468
469 //---------------------------------------------------------------------------------------------------------------------
470 /**
471 * @brief Clear clear list of points.
472 */
Clear()473 void VSplinePath::Clear()
474 {
475 d->path.clear();
476 SetDuplicate(0);
477 }
478