1 /************************************************************************
2 **
3 ** @file vabstractcubicbezierpath.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date 16 3, 2016
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) 2016 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 "vabstractcubicbezierpath.h"
30 #include "vsplinepoint.h"
31
32 #include <QPainterPath>
33
34 #include "../vmisc/def.h"
35 #include "../ifc/ifcdef.h"
36 #include "../ifc/exception/vexception.h"
37 #include "vpointf.h"
38 #include "vspline.h"
39
40 //---------------------------------------------------------------------------------------------------------------------
VAbstractCubicBezierPath(const GOType & type,const quint32 & idObject,const Draw & mode)41 VAbstractCubicBezierPath::VAbstractCubicBezierPath(const GOType &type, const quint32 &idObject, const Draw &mode)
42 : VAbstractBezier(type, idObject, mode)
43 {
44 }
45
46 //---------------------------------------------------------------------------------------------------------------------
VAbstractCubicBezierPath(const VAbstractCubicBezierPath & curve)47 VAbstractCubicBezierPath::VAbstractCubicBezierPath(const VAbstractCubicBezierPath &curve)
48 : VAbstractBezier(curve)
49 {
50 }
51
52 //---------------------------------------------------------------------------------------------------------------------
operator =(const VAbstractCubicBezierPath & curve)53 VAbstractCubicBezierPath &VAbstractCubicBezierPath::operator=(const VAbstractCubicBezierPath &curve)
54 {
55 if ( &curve == this )
56 {
57 return *this;
58 }
59 VAbstractBezier::operator=(curve);
60 return *this;
61 }
62
63 //---------------------------------------------------------------------------------------------------------------------
~VAbstractCubicBezierPath()64 VAbstractCubicBezierPath::~VAbstractCubicBezierPath()
65 {
66 }
67
68 //---------------------------------------------------------------------------------------------------------------------
69 /**
70 * @brief GetPath return QPainterPath which reprezent spline path.
71 * @return path.
72 */
GetPath() const73 QPainterPath VAbstractCubicBezierPath::GetPath() const
74 {
75 QPainterPath painterPath;
76 for (qint32 i = 1; i <= CountSubSpl(); ++i)
77 {
78 painterPath.addPath(GetSpline(i).GetPath());
79 }
80 return painterPath;
81 }
82
83 //---------------------------------------------------------------------------------------------------------------------
84 /**
85 * @brief GetPathPoints return list of points what located on path.
86 * @return list.
87 */
GetPoints() const88 QVector<QPointF> VAbstractCubicBezierPath::GetPoints() const
89 {
90 QVector<QPointF> pathPoints;
91 for (qint32 i = 1; i <= CountSubSpl(); ++i)
92 {
93 if (not pathPoints.isEmpty())
94 {
95 pathPoints.removeLast();
96 }
97
98 pathPoints += GetSpline(i).GetPoints();
99 }
100 return pathPoints;
101 }
102
103 //---------------------------------------------------------------------------------------------------------------------
104 /**
105 * @brief GetLength return length of spline path.
106 * @return length.
107 */
GetLength() const108 qreal VAbstractCubicBezierPath::GetLength() const
109 {
110 qreal length = 0;
111 for (qint32 i = 1; i <= CountSubSpl(); ++i)
112 {
113 length += GetSpline(i).GetLength();
114 }
115 return length;
116 }
117
118 //---------------------------------------------------------------------------------------------------------------------
DirectionArrows() const119 QVector<DirectionArrow> VAbstractCubicBezierPath::DirectionArrows() const
120 {
121 QVector<DirectionArrow> arrows;
122 for (qint32 i = 1; i <= CountSubSpl(); ++i)
123 {
124 arrows += GetSpline(i).DirectionArrows();
125 }
126 return arrows;
127 }
128
129 //---------------------------------------------------------------------------------------------------------------------
Segment(const QPointF & p) const130 int VAbstractCubicBezierPath::Segment(const QPointF &p) const
131 {
132 int index = -1;
133 for (qint32 i = 1; i <= CountSubSpl(); ++i)
134 {
135 const qreal t = GetSpline(i).ParamT(p);
136 if (qFuzzyIsNull(t) || not qFuzzyCompare(t, -1))
137 {
138 index = i;
139 break;
140 }
141 }
142 return index;
143 }
144
145 //---------------------------------------------------------------------------------------------------------------------
146 /**
147 * @brief CutSplinePath cut spline path into two. This method don't return two spline path. You must create spline
148 * paths by yourself.
149 * Example:
150 * QPointF spl1p2, spl1p3, spl2p2, spl2p3;
151 * qint32 p1 = 0, p2 = 0;
152 * QPointF point = splPath->CutSplinePath(length, p1, p2, spl1p2, spl1p3, spl2p2, spl2p3);
153 *
154 * VSplinePoint splP1 = splPath->at(p1);
155 * VSplinePoint splP2 = splPath->at(p2);
156 * VSpline spl1 = VSpline(splP1.P(), spl1p2, spl1p3, *p, splPath->GetKCurve());
157 * VSpline spl2 = VSpline(*p, spl2p2, spl2p3, splP2.P(), splPath->GetKCurve());
158 * @param length length first spline path.
159 * @param p1 index first spline point in list.
160 * @param p2 index second spline point in list.
161 * @param spl1p2 first control point first spline.
162 * @param spl1p3 second control point first spline.
163 * @param spl2p2 first control point second spline.
164 * @param spl2p3 second control point second spline.
165 * @return cutting point.
166 */
CutSplinePath(qreal length,qint32 & p1,qint32 & p2,QPointF & spl1p2,QPointF & spl1p3,QPointF & spl2p2,QPointF & spl2p3) const167 QPointF VAbstractCubicBezierPath::CutSplinePath(qreal length, qint32 &p1, qint32 &p2, QPointF &spl1p2, QPointF &spl1p3,
168 QPointF &spl2p2, QPointF &spl2p3) const
169 {
170 if (CountSubSpl() < 1)
171 {
172 throw VException(tr("Can't cut this spline"));
173 }
174
175 //Always need return two spline paths, so we must correct wrong length.
176 const qreal minLength = ToPixel(1, Unit::Mm);
177 qreal fullLength = GetLength();
178
179 if (fullLength <= minLength)
180 {
181 p1 = p2 = -1;
182 spl1p2 = spl1p3 = spl2p2 = spl2p3 = QPointF();
183 return QPointF();
184 }
185
186 const qreal maxLength = fullLength - minLength;
187
188 if (length < minLength)
189 {
190 length = minLength;
191 }
192 else if (length > maxLength)
193 {
194 length = maxLength;
195 }
196
197 fullLength = 0;
198 for (qint32 i = 1; i <= CountSubSpl(); ++i)
199 {
200 const VSpline spl = GetSpline(i);
201 const qreal splLength = spl.GetLength();
202 fullLength += splLength;
203 if (fullLength > length)
204 {
205 p1 = i-1;
206 p2 = i;
207 const QPointF point = spl.CutSpline(length - (fullLength - splLength), spl1p2, spl1p3, spl2p2, spl2p3);
208
209 const QVector<VSplinePoint> points = GetSplinePath();
210
211 if (p1 > 0)
212 {
213 const VSplinePoint splP1 = points.at(p1);
214 QLineF line(splP1.P().toQPointF(), spl1p2);
215 if (qFuzzyIsNull(line.length()))
216 {
217 spl1p2.rx() += ToPixel(0.1, Unit::Mm);
218 QLineF line(splP1.P().toQPointF(), spl1p2);
219 line.setLength(ToPixel(0.1, Unit::Mm));
220 line.setAngle(splP1.Angle1()+180);
221 spl1p2 = line.p2();
222 }
223 }
224
225 if (p2 < points.size() - 1)
226 {
227 const VSplinePoint splP2 = points.at(p2);
228 QLineF line(splP2.P().toQPointF(), spl2p3);
229 if (qFuzzyIsNull(line.length()))
230 {
231 spl2p3.rx() += ToPixel(0.1, Unit::Mm);
232 QLineF line(splP2.P().toQPointF(), spl2p3);
233 line.setAngle(splP2.Angle2()+180);
234 spl2p3 = line.p2();
235 }
236 }
237
238 return point;
239 }
240 }
241 p1 = p2 = -1;
242 spl1p2 = spl1p3 = spl2p2 = spl2p3 = QPointF();
243 return QPointF();
244 }
245
246 //---------------------------------------------------------------------------------------------------------------------
247 /**
248 * @brief NameForHistory helps to create name for dialog History.
249 * @param toolName first part of name. Like 'Spline path' or 'Cubic Bezier path'.
250 * @return name of curve for history records.
251 */
NameForHistory(const QString & toolName) const252 QString VAbstractCubicBezierPath::NameForHistory(const QString &toolName) const
253 {
254 QString name = toolName;
255 if (CountPoints() > 0)
256 {
257 name += QString(" %1").arg(FirstPoint().name());
258 if (CountSubSpl() >= 1)
259 {
260 name += QString("_%1").arg(LastPoint().name());
261 }
262
263 if (GetDuplicate() > 0)
264 {
265 name += QString("_%1").arg(GetDuplicate());
266 }
267 }
268
269 QString alias;
270
271 if (not GetAliasSuffix().isEmpty())
272 {
273 alias = QString("%1 %2").arg(toolName, GetAliasSuffix());
274 }
275
276 return not alias.isEmpty() ? QString("%1 (%2)").arg(alias, name) : name;
277 }
278
279 //---------------------------------------------------------------------------------------------------------------------
CreateName()280 void VAbstractCubicBezierPath::CreateName()
281 {
282 QString name;
283 if (CountPoints() > 0)
284 {
285 name = splPath;
286 name.append(QString("_%1").arg(FirstPoint().name()));
287 if (CountSubSpl() >= 1)
288 {
289 name.append(QString("_%1").arg(LastPoint().name()));
290
291 if (GetDuplicate() > 0)
292 {
293 name += QString("_%1").arg(GetDuplicate());
294 }
295 }
296 }
297 setName(name);
298 }
299
300 //---------------------------------------------------------------------------------------------------------------------
CreateAlias()301 void VAbstractCubicBezierPath::CreateAlias()
302 {
303 const QString aliasSuffix = GetAliasSuffix();
304 if (aliasSuffix.isEmpty())
305 {
306 SetAlias(QString());
307 return;
308 }
309
310 SetAlias(splPath + '_' + aliasSuffix);
311 }
312