Seamly2D
Code documentation
varc.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 varc.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date November 15, 2013
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) 2013-2015 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 "varc.h"
53 
54 #include <QLineF>
55 #include <QPointF>
56 
57 #include "../vmisc/def.h"
58 #include "../vmisc/vmath.h"
59 #include "../ifc/ifcdef.h"
60 #include "vabstractcurve.h"
61 #include "varc_p.h"
62 #include "vspline.h"
63 
64 //---------------------------------------------------------------------------------------------------------------------
65 /**
66  * @brief VArc default constructor.
67  */
70  d (new VArcData)
71 {}
72 
73 //---------------------------------------------------------------------------------------------------------------------
74 /**
75  * @brief VArc constructor.
76  * @param center center point.
77  * @param radius arc radius.
78  * @param f1 start angle (degree).
79  * @param f2 end angle (degree).
80  */
81 
82 #ifdef Q_COMPILER_RVALUE_REFS
83 VArc &VArc::operator=(VArc &&arc) Q_DECL_NOTHROW
84 { Swap(arc); return *this; }
85 #endif
86 
87 void VArc::Swap(VArc &arc) Q_DECL_NOTHROW
88 { VAbstractArc::Swap(arc); std::swap(d, arc.d); }
89 
90 VArc::VArc (const VPointF &center, qreal radius, const QString &formulaRadius, qreal f1, const QString &formulaF1,
91  qreal f2, const QString &formulaF2, quint32 idObject, Draw mode)
92  : VAbstractArc(GOType::Arc, center, f1, formulaF1, f2, formulaF2, idObject, mode),
93  d (new VArcData(radius, formulaRadius))
94 {
95  CreateName();
96 }
97 
98 //---------------------------------------------------------------------------------------------------------------------
99 VArc::VArc(const VPointF &center, qreal radius, qreal f1, qreal f2)
100  : VAbstractArc(GOType::Arc, center, f1, f2, NULL_ID, Draw::Calculation),
101  d (new VArcData(radius))
102 {
103  CreateName();
104 }
105 
106 //---------------------------------------------------------------------------------------------------------------------
107 VArc::VArc(qreal length, const QString &formulaLength, const VPointF &center, qreal radius,
108  const QString &formulaRadius, qreal f1, const QString &formulaF1, quint32 idObject, Draw mode)
109  : VAbstractArc(GOType::Arc, formulaLength, center, f1, formulaF1, idObject, mode),
110  d (new VArcData(radius, formulaRadius))
111 {
112  CreateName();
113  FindF2(length);
114 }
115 
116 //---------------------------------------------------------------------------------------------------------------------
117 VArc::VArc(qreal length, const VPointF &center, qreal radius, qreal f1)
118  : VAbstractArc(GOType::Arc, center, f1, NULL_ID, Draw::Calculation),
119  d (new VArcData(radius))
120 {
121  CreateName();
122  FindF2(length);
123 }
124 
125 //---------------------------------------------------------------------------------------------------------------------
126 /**
127  * @brief VArc copy constructor
128  * @param arc arc
129  */
130 VArc::VArc(const VArc &arc)
131  : VAbstractArc(arc), d (arc.d)
132 {}
133 
134 //---------------------------------------------------------------------------------------------------------------------
135 /**
136  * @brief operator = assignment operator
137  * @param arc arc
138  * @return arc
139  */
141 {
142  if ( &arc == this )
143  {
144  return *this;
145  }
147  d = arc.d;
148  return *this;
149 }
150 
151 //---------------------------------------------------------------------------------------------------------------------
152 VArc VArc::Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix) const
153 {
154  const VPointF center = GetCenter().Rotate(originPoint, degrees);
155 
156  const QPointF p1 = VPointF::RotatePF(originPoint, GetP1(), degrees);
157  const QPointF p2 = VPointF::RotatePF(originPoint, GetP2(), degrees);
158 
159  const qreal f1 = QLineF(static_cast<QPointF>(center), p1).angle();
160  const qreal f2 = QLineF(static_cast<QPointF>(center), p2).angle();
161 
162  VArc arc(center, GetRadius(), f1, f2);
163  arc.setName(name() + prefix);
164  arc.setLineColor(getLineColor());
165  arc.SetPenStyle(GetPenStyle());
167  arc.SetFlipped(IsFlipped());
168  return arc;
169 }
170 
171 //---------------------------------------------------------------------------------------------------------------------
172 VArc VArc::Flip(const QLineF &axis, const QString &prefix) const
173 {
174  const VPointF center = GetCenter().Flip(axis);
175 
176  const QPointF p1 = VPointF::FlipPF(axis, GetP1());
177  const QPointF p2 = VPointF::FlipPF(axis, GetP2());
178 
179  const qreal f1 = QLineF(static_cast<QPointF>(center), p1).angle();
180  const qreal f2 = QLineF(static_cast<QPointF>(center), p2).angle();
181 
182  VArc arc(center, GetRadius(), f1, f2);
183  arc.setName(name() + prefix);
184  arc.setLineColor(getLineColor());
185  arc.SetPenStyle(GetPenStyle());
187  arc.SetFlipped(not IsFlipped());
188  return arc;
189 }
190 
191 //---------------------------------------------------------------------------------------------------------------------
192 VArc VArc::Move(qreal length, qreal angle, const QString &prefix) const
193 {
194  const VPointF center = GetCenter().Move(length, angle);
195 
196  const QPointF p1 = VPointF::MovePF(GetP1(), length, angle);
197  const QPointF p2 = VPointF::MovePF(GetP2(), length, angle);
198 
199  const qreal f1 = QLineF(static_cast<QPointF>(center), p1).angle();
200  const qreal f2 = QLineF(static_cast<QPointF>(center), p2).angle();
201 
202  VArc arc(center, GetRadius(), f1, f2);
203  arc.setName(name() + prefix);
204  arc.setLineColor(getLineColor());
205  arc.SetPenStyle(GetPenStyle());
207  arc.SetFlipped(IsFlipped());
208  return arc;
209 }
210 
211 //---------------------------------------------------------------------------------------------------------------------
213 {}
214 
215 //---------------------------------------------------------------------------------------------------------------------
216 /**
217  * @brief GetLength return arc length.
218  * @return length.
219  */
220 qreal VArc::GetLength() const
221 {
222  qreal length = d->radius * qDegreesToRadians(AngleArc());
223  if (IsFlipped())
224  {
225  length *= -1;
226  }
227 
228  return length;
229 }
230 
231 //---------------------------------------------------------------------------------------------------------------------
232 /**
233  * @brief GetP1 return point associated with start angle.
234  * @return point.
235  */
236 QPointF VArc::GetP1() const
237 {
238  QPointF p1 ( GetCenter().x () + d->radius, GetCenter().y () );
239  QLineF centerP1(static_cast<QPointF>(GetCenter()), p1);
240  centerP1.setAngle(GetStartAngle());
241  return centerP1.p2();
242 }
243 
244 //---------------------------------------------------------------------------------------------------------------------
245 /**
246  * @brief GetP2 return point associated with end angle.
247  * @return точку point.
248  */
249 QPointF VArc::GetP2 () const
250 {
251  QPointF p2 ( GetCenter().x () + d->radius, GetCenter().y () );
252  QLineF centerP2(static_cast<QPointF>(GetCenter()), p2);
253  centerP2.setAngle(GetEndAngle());
254  return centerP2.p2();
255 }
256 
257 //---------------------------------------------------------------------------------------------------------------------
258 /**
259  * @brief GetPoints return list of points needed for drawing arc.
260  * @return list of points
261  */
263 {
264  QVector<QPointF> points;
265  QVector<qreal> sectionAngle;
266 
267  QPointF pStart;
268  IsFlipped() ? pStart = GetP2() : pStart = GetP1();
269 
270  {
271  qreal angle = AngleArc();
272 
273  if (qFuzzyIsNull(angle))
274  {
275  points.append(pStart);
276  return points;
277  }
278 
279  if (angle > 360 || angle < 0)
280  {// Filter incorect value
281  QLineF dummy(0,0, 100, 0);
282  dummy.setAngle(angle);
283  angle = dummy.angle();
284  }
285 
286  const qreal angleInterpolation = 45; //degree
287  const int sections = qFloor(angle / angleInterpolation);
288  for (int i = 0; i < sections; ++i)
289  {
290  sectionAngle.append(angleInterpolation);
291  }
292 
293  const qreal tail = angle - sections * angleInterpolation;
294  if (tail > 0)
295  {
296  sectionAngle.append(tail);
297  }
298  }
299 
300  for (int i = 0; i < sectionAngle.size(); ++i)
301  {
302  const qreal lDistance = GetRadius() * 4.0/3.0 * qTan(qDegreesToRadians(sectionAngle.at(i)) * 0.25);
303 
304  const QPointF center = static_cast<QPointF>(GetCenter());
305 
306  QLineF lineP1P2(pStart, center);
307  lineP1P2.setAngle(lineP1P2.angle() - 90.0);
308  lineP1P2.setLength(lDistance);
309 
310  QLineF lineP4P3(center, pStart);
311  lineP4P3.setAngle(lineP4P3.angle() + sectionAngle.at(i));
312  lineP4P3.setLength(GetRadius());//in case of computing error
313  lineP4P3 = QLineF(lineP4P3.p2(), center);
314  lineP4P3.setAngle(lineP4P3.angle() + 90.0);
315  lineP4P3.setLength(lDistance);
316 
317  VSpline spl(VPointF(pStart), lineP1P2.p2(), lineP4P3.p2(), VPointF(lineP4P3.p1()), 1.0);
318  QVector<QPointF> splPoints = spl.getPoints();
319  if (not splPoints.isEmpty() && i != sectionAngle.size() - 1)
320  {
321  splPoints.removeLast();
322  }
323 
324  points << splPoints;
325  pStart = lineP4P3.p1();
326  }
327  return points;
328 }
329 
330 //---------------------------------------------------------------------------------------------------------------------
332 {
333  QVector<QPointF> points = getPoints();
334  QVector<QLineF> lines;
335  if (points.size() >= 2)
336  {
337  for (int i=0; i < points.size()-1; ++i)
338  {
339  QLineF segment = QLineF(points.at(i), points.at(i+1));
340  if (segment.length() > 0)
341  {
342  lines.append(segment);
343  }
344  }
345  }
346  return lines;
347 }
348 
349 //---------------------------------------------------------------------------------------------------------------------
350 /**
351  * @brief CutArc cut arc into two segments.
352  * @param length length first arc segment.
353  * @param segment1 first arc segment.
354  * @param segment2 second arc segment.
355  * @return point cutting
356  */
357 QPointF VArc::CutArc(qreal length, VArc &segment1, VArc &segment2) const
358 {
359  //Always need to return two arc segments, so we must correct wrong length.
360  const qreal minLength = ToPixel(2, Unit::Mm);
361  const qreal fullLength = GetLength();
362 
363  if (qAbs(fullLength) <= minLength)
364  {
365  segment1 = VArc();
366  segment2 = VArc();
367  return QPointF();
368  }
369 
370  QLineF line(static_cast<QPointF>(GetCenter()), GetP1());
371 
372  if (not IsFlipped())
373  {
374  if (length < 0)
375  {
376  length = fullLength + length;
377  }
378  length = qBound(ToPixel(1, Unit::Mm), length, fullLength - ToPixel(1, Unit::Mm));
379 
380  line.setAngle(line.angle() + qRadiansToDegrees(length/d->radius));
381  }
382  else
383  {
384  if (length > 0)
385  {
386  length = fullLength + length;
387  }
388  length = qBound(fullLength + ToPixel(1, Unit::Mm), length, ToPixel(-1, Unit::Mm));
389 
390  line.setAngle(line.angle() - qRadiansToDegrees(qAbs(length)/d->radius));
391  }
392 
393  segment1 = VArc (GetCenter(), d->radius, d->formulaRadius, GetStartAngle(), GetFormulaF1(), line.angle(),
394  QString().setNum(line.angle()), getIdObject(), getMode());
395  segment1.SetFlipped(IsFlipped());
396 
397  segment2 = VArc (GetCenter(), d->radius, d->formulaRadius, line.angle(), QString().setNum(line.angle()), GetEndAngle(),
399  segment2.SetFlipped(IsFlipped());
400 
401  return line.p2();
402 }
403 
404 
405 //---------------------------------------------------------------------------------------------------------------------
406 QPointF VArc::CutArc(qreal length) const
407 {
408  VArc segment1;
409  VArc segment2;
410  return this->CutArc(length, segment1, segment2);
411 }
412 
413 //---------------------------------------------------------------------------------------------------------------------
415 {
416  QString name = ARC_ + QString("%1").arg(this->GetCenter().name());
417 
418  if (VAbstractCurve::id() != NULL_ID)
419  {
420  name += QString("_%1").arg(VAbstractCurve::id());
421  }
422 
423  if (GetDuplicate() > 0)
424  {
425  name += QString("_%1").arg(GetDuplicate());
426  }
427 
428  setName(name);
429 }
430 
431 //---------------------------------------------------------------------------------------------------------------------
432 void VArc::FindF2(qreal length)
433 {
434  SetFlipped(length < 0);
435 
436  if (length >= MaxLength())
437  {
438  length = MaxLength();
439  }
440 
441  qreal arcAngle = qAbs(qRadiansToDegrees(length/d->radius));
442 
443  if (IsFlipped())
444  {
445  arcAngle = arcAngle * -1;
446  }
447 
448  QLineF startAngle(0, 0, 100, 0);
449  startAngle.setAngle(GetStartAngle() + arcAngle);// We use QLineF just because it is easy way correct angle value
450 
451  SetFormulaF2(QString().number(startAngle.angle()), startAngle.angle());
452 }
453 
454 //---------------------------------------------------------------------------------------------------------------------
455 qreal VArc::MaxLength() const
456 {
457  return M_2PI*d->radius;
458 }
459 
460 //---------------------------------------------------------------------------------------------------------------------
461 /**
462  * @brief GetRadius return arc radius.
463  * @return radius.
464  */
465 QString VArc::GetFormulaRadius() const
466 {
467  return d->formulaRadius;
468 }
469 
470 //---------------------------------------------------------------------------------------------------------------------
471 void VArc::SetFormulaRadius(const QString &formula, qreal value)
472 {
473  d->formulaRadius = formula;
474  d->radius = value;
475 }
476 
477 //---------------------------------------------------------------------------------------------------------------------
478 /**
479  * @brief GetRadius return formula for radius.
480  * @return string with formula.
481  */
482 qreal VArc::GetRadius() const
483 {
484  return d->radius;
485 }
qreal AngleArc() const
void Swap(VAbstractArc &arc) Q_DECL_NOTHROW
virtual VPointF GetCenter() const
QString GetFormulaF1() const
VAbstractArc & operator=(const VAbstractArc &arc)
QString GetFormulaF2() const
void SetFormulaF2(const QString &formula, qreal value)
virtual qreal GetEndAngle() const Q_DECL_OVERRIDE
virtual qreal GetStartAngle() const Q_DECL_OVERRIDE
bool IsFlipped() const
void SetFlipped(bool value)
QString getLineWeight() const
getLineWeight return weight of the lines
void SetPenStyle(const QString &penStyle)
void setLineColor(const QString &color)
void setLineWeight(const QString &lineWeight)
setLineWeight set weight of the lines
QString GetPenStyle() const
quint32 GetDuplicate() const
QString getLineColor() const
VArc class for anticlockwise arc.
Definition: varc.h:74
QPointF GetP2() const
GetP2 return point associated with end angle.
Definition: varc.cpp:249
virtual void FindF2(qreal length) Q_DECL_OVERRIDE
Definition: varc.cpp:432
VArc()
VArc default constructor.
Definition: varc.cpp:68
virtual ~VArc() Q_DECL_OVERRIDE
Definition: varc.cpp:212
QPointF CutArc(qreal length, VArc &segment1, VArc &segment2) const
CutArc cut arc into two segments.
Definition: varc.cpp:357
virtual void CreateName() Q_DECL_OVERRIDE
Definition: varc.cpp:414
VArc Move(qreal length, qreal angle, const QString &prefix=QString()) const
Definition: varc.cpp:192
QVector< QLineF > getSegments() const
Definition: varc.cpp:331
virtual qreal GetLength() const Q_DECL_OVERRIDE
GetLength return arc length.
Definition: varc.cpp:220
VArc Flip(const QLineF &axis, const QString &prefix=QString()) const
Definition: varc.cpp:172
QString GetFormulaRadius() const
GetRadius return arc radius.
Definition: varc.cpp:465
VArc Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix=QString()) const
Definition: varc.cpp:152
VArc & operator=(const VArc &arc)
operator = assignment operator
Definition: varc.cpp:140
qreal MaxLength() const
Definition: varc.cpp:455
qreal GetRadius() const
GetRadius return formula for radius.
Definition: varc.cpp:482
void Swap(VArc &arc) Q_DECL_NOTHROW
VArc constructor.
Definition: varc.cpp:87
QPointF GetP1() const
GetP1 return point associated with start angle.
Definition: varc.cpp:236
virtual QVector< QPointF > getPoints() const Q_DECL_OVERRIDE
GetPoints return list of points needed for drawing arc.
Definition: varc.cpp:262
void SetFormulaRadius(const QString &formula, qreal value)
Definition: varc.cpp:471
QSharedDataPointer< VArcData > d
Definition: varc.h:119
virtual QString name() const
name return name graphical object.
Definition: vgobject.cpp:148
quint32 getIdObject() const
getIdObject return parent id.
Definition: vgobject.cpp:128
void setName(const QString &name)
setName set name graphical object.
Definition: vgobject.cpp:158
Draw getMode() const
getMode return mode creation.
Definition: vgobject.cpp:168
quint32 id() const
id return id object.
Definition: vgobject.cpp:205
The VPointF class keep data of point.
Definition: vpointf.h:75
static QPointF RotatePF(const QPointF &originPoint, const QPointF &point, qreal degrees)
Definition: vpointf.cpp:271
static QPointF MovePF(const QPointF &originPoint, qreal length, qreal angle)
Definition: vpointf.cpp:286
VPointF Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix=QString()) const
Definition: vpointf.cpp:146
VPointF Flip(const QLineF &axis, const QString &prefix=QString()) const
Definition: vpointf.cpp:155
VPointF Move(qreal length, qreal angle, const QString &prefix=QString()) const
Definition: vpointf.cpp:164
static QPointF FlipPF(const QLineF &axis, const QPointF &point)
Definition: vpointf.cpp:279
VSpline class that implements the spline.
Definition: vspline.h:75
virtual QVector< QPointF > getPoints() const Q_DECL_OVERRIDE
GetPoints return list with spline points.
Definition: vspline.cpp:228
double ToPixel(double val, const Unit &unit)
Definition: def.cpp:231
#define ARC_
Definition: ifcdef.h:239
#define NULL_ID
Definition: ifcdef.h:76
GOType
Definition: vgeometrydef.h:56
Draw
Definition: vgeometrydef.h:55
@ Calculation
#define M_2PI
Definition: vmath.h:27