Seamly2D
Code documentation
vabstractcurve.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 vabstractcurve.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date 25 6, 2014
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 "vabstractcurve.h"
53 
54 #include <QLine>
55 #include <QLineF>
56 #include <QMessageLogger>
57 #include <QPainterPath>
58 #include <QPoint>
59 #include <QtDebug>
60 
61 #include "vabstractcurve_p.h"
62 
64 
65 #ifdef Q_COMPILER_RVALUE_REFS
67 { Swap(curve); return *this; }
68 #endif
69 
70 void VAbstractCurve::Swap(VAbstractCurve &curve) Q_DECL_NOTHROW
71 { VGObject::Swap(curve); std::swap(d, curve.d); }
72 
73 VAbstractCurve::VAbstractCurve(const GOType &type, const quint32 &idObject, const Draw &mode)
74  :VGObject(type, idObject, mode), d (new VAbstractCurveData())
75 {}
76 
77 //---------------------------------------------------------------------------------------------------------------------
79  :VGObject(curve), d (curve.d)
80 {}
81 
82 //---------------------------------------------------------------------------------------------------------------------
84 {
85  if ( &curve == this )
86  {
87  return *this;
88  }
89  VGObject::operator=(curve);
90  d = curve.d;
91  return *this;
92 }
93 
94 //---------------------------------------------------------------------------------------------------------------------
96 {}
97 
98 //---------------------------------------------------------------------------------------------------------------------
100  const QPointF &end, bool reverse)
101 {
102  QVector<QPointF> segment = points;
103  if (reverse)
104  {
105  segment = GetReversePoints(segment);
106  }
107 
108  QPointF start = begin;
109  QPointF finish = end;
110 
111  if (begin == end)
112  {
113  start = segment.first();
114  finish = segment.last();
115  }
116 
117  segment = FromBegin(segment, start);
118  segment = ToEnd(segment, finish);
119  return segment;
120 }
121 
122 //---------------------------------------------------------------------------------------------------------------------
123 QVector<QPointF> VAbstractCurve::GetSegmentPoints(const QPointF &begin, const QPointF &end, bool reverse) const
124 {
125  return GetSegmentPoints(getPoints(), begin, end, reverse);
126 }
127 
128 //---------------------------------------------------------------------------------------------------------------------
129 QVector<QPointF> VAbstractCurve::FromBegin(const QVector<QPointF> &points, const QPointF &begin, bool *ok)
130 {
131  if (points.count() >= 2)
132  {
133  if (points.first().toPoint() == begin.toPoint())
134  {
135  if (ok != nullptr)
136  {
137  *ok = true;
138  }
139  return points;
140  }
141 
142  QVector<QPointF> segment;
143  bool theBegin = false;
144  for (qint32 i = 0; i < points.count()-1; ++i)
145  {
146  if (theBegin == false)
147  {
148  if (IsPointOnLineSegment(begin, points.at(i), points.at(i+1)))
149  {
150  theBegin = true;
151 
152  if (begin != points.at(i+1))
153  {
154  segment.append(begin);
155  }
156 
157  if (i == points.count()-2)
158  {
159  segment.append(points.at(i+1));
160  }
161  }
162  }
163  else
164  {
165  segment.append(points.at(i));
166  if (i == points.count()-2)
167  {
168  segment.append(points.at(i+1));
169  }
170  }
171  }
172 
173  if (segment.isEmpty())
174  {
175  if (ok != nullptr)
176  {
177  *ok = false;
178  }
179  return points;
180  }
181  else
182  {
183  if (ok != nullptr)
184  {
185  *ok = true;
186  }
187  return segment;
188  }
189  }
190  else
191  {
192  if (ok != nullptr)
193  {
194  *ok = false;
195  }
196  return points;
197  }
198 }
199 
200 //---------------------------------------------------------------------------------------------------------------------
201 QVector<QPointF> VAbstractCurve::ToEnd(const QVector<QPointF> &points, const QPointF &end, bool *ok)
202 {
203  QVector<QPointF> reversed = GetReversePoints(points);
204  reversed = FromBegin(reversed, end, ok);
205  return GetReversePoints(reversed);
206 }
207 
208 //---------------------------------------------------------------------------------------------------------------------
209 QPainterPath VAbstractCurve::GetPath() const
210 {
211  QPainterPath path;
212 
213  const QVector<QPointF> points = getPoints();
214  if (points.count() >= 2)
215  {
216  path.addPolygon(QPolygonF(points));
217  }
218  else
219  {
220  qDebug()<<"points.count() < 2"<<Q_FUNC_INFO;
221  }
222  return path;
223 }
224 
225 //---------------------------------------------------------------------------------------------------------------------
226 qreal VAbstractCurve::GetLengthByPoint(const QPointF &point) const
227 {
228  const QVector<QPointF> points = getPoints();
229  if (points.size() < 2)
230  {
231  return -1;
232  }
233 
234  if (points.first().toPoint() == point.toPoint())
235  {
236  return 0;
237  }
238 
239  bool ok = false;
240  const QVector<QPointF> segment = ToEnd(points, point, &ok);
241  if (not ok)
242  {
243  return -1;
244  }
245  return PathLength(segment);
246 }
247 
248 //---------------------------------------------------------------------------------------------------------------------
249 /**
250  * @brief IntersectLine return list of points for real intersection with line
251  * @param line line that intersect with curve
252  * @return list of intersection points
253  */
255 {
256  return CurveIntersectLine(this->getPoints(), line);
257 }
258 
259 //---------------------------------------------------------------------------------------------------------------------
260 bool VAbstractCurve::IsIntersectLine(const QLineF &line) const
261 {
262  const QVector<QPointF> points = IntersectLine(line);
263  return not points.isEmpty();
264 }
265 
266 //---------------------------------------------------------------------------------------------------------------------
267 bool VAbstractCurve::isPointOnCurve(const QVector<QPointF> &points, const QPointF &p)
268 {
269  if (points.isEmpty())
270  {
271  return false;
272  }
273  else if (points.size() < 2)
274  {
275  return points.at(0) == p;
276  }
277  else
278  {
279  for (qint32 i = 0; i < points.count()-1; ++i)
280  {
281  if (IsPointOnLineSegment(p, points.at(i), points.at(i+1)))
282  {
283  return true;
284  }
285  }
286  }
287 
288  return false;
289 }
290 
291 //---------------------------------------------------------------------------------------------------------------------
292 bool VAbstractCurve::isPointOnCurve(const QPointF &p) const
293 {
294  return isPointOnCurve(getPoints(), p);
295 }
296 
297 //---------------------------------------------------------------------------------------------------------------------
299 {
300  return d->duplicate;
301 }
302 
303 //---------------------------------------------------------------------------------------------------------------------
304 void VAbstractCurve::SetDuplicate(quint32 number)
305 {
306  d->duplicate = number;
307  CreateName();
308 }
309 
310 //---------------------------------------------------------------------------------------------------------------------
312 {
313  return d->color;
314 }
315 
316 //---------------------------------------------------------------------------------------------------------------------
317 void VAbstractCurve::setLineColor(const QString &color)
318 {
319  d->color = color;
320 }
321 
322 //---------------------------------------------------------------------------------------------------------------------
324 {
325  return d->penStyle;
326 }
327 
328 //---------------------------------------------------------------------------------------------------------------------
329 void VAbstractCurve::SetPenStyle(const QString &penStyle)
330 {
331  d->penStyle = penStyle;
332 }
333 
334 //---------------------------------------------------------------------------------------------------------------------
335 /**
336  * @brief getLineWeight return weight of the lines
337  * @return lineWeight
338  */
340 {
341  return d->lineWeight;
342 }
343 
344 //---------------------------------------------------------------------------------------------------------------------
345 /**
346  * @brief setLineWeight set weight of the lines
347  * @param lineWeight type
348  */
349 void VAbstractCurve::setLineWeight(const QString &lineWeight)
350 {
351  d->lineWeight = lineWeight;
352 }
353 
354 //---------------------------------------------------------------------------------------------------------------------
356 {
357  QVector<QPointF> intersections;
358  for ( auto i = 0; i < points.count()-1; ++i )
359  {
360  QPointF crosPoint;
361  const auto type = line.intersects(QLineF(points.at(i), points.at(i+1)), &crosPoint);
362  if ( type == QLineF::BoundedIntersection )
363  {
364  intersections.append(crosPoint);
365  }
366  }
367  return intersections;
368 }
369 
370 //---------------------------------------------------------------------------------------------------------------------
372 {
374 
375  const QVector<QPointF> points = getPoints();
376  if (points.count() >= 2)
377  {
378  /*Need find coordinate midle of curve.
379  Universal way is take all points and find sum.*/
380  const qreal seek_length = qAbs(GetLength())/2.0;
381  qreal found_length = 0;
382  QLineF arrow;
383  for (qint32 i = 1; i <= points.size()-1; ++i)
384  {
385  arrow = QLineF(points.at(i-1), points.at(i));
386  found_length += arrow.length();//Length that we aready find
387 
388  if (seek_length <= found_length)// if have found more that need stop.
389  {
390  //subtract length in last line and you will find position of the middle point.
391  arrow.setLength(arrow.length() - (found_length - seek_length));
392  break;
393  }
394  }
395 
396  //Reverse line because we want start arrow from this point
397  arrow = QLineF(arrow.p2(), arrow.p1());
398  const qreal angle = arrow.angle();//we each time change line angle, better save original angle value
399  arrow.setLength(lengthCurveDirectionArrow);//arrow length in pixels
400 
401  DirectionArrow dArrow;
402 
403  arrow.setAngle(angle-35);
404  dArrow.first = arrow;
405 
406  arrow.setAngle(angle+35);
407  dArrow.second = arrow;
408 
409  arrows.append(dArrow);
410  }
411  return arrows;
412 }
413 
414 //---------------------------------------------------------------------------------------------------------------------
415 QPainterPath VAbstractCurve::ShowDirection(const QVector<DirectionArrow> &arrows, qreal width)
416 {
417  QPainterPath path;
418 
419  for (int i = 0; i < arrows.size(); ++i)
420  {
421  const DirectionArrow arrow = arrows.at(i);
422  if (not arrow.first.isNull() && not arrow.second.isNull())
423  {
424  QPainterPath arrowPath;
425 
426  QLineF line = arrow.first;
427  line.setLength(width);
428  arrowPath.moveTo(line.p1());
429  arrowPath.lineTo(line.p2());
430 
431  line = arrow.second;
432  line.setLength(width);
433  arrowPath.moveTo(line.p1());
434  arrowPath.lineTo(line.p2());
435 
436  path.addPath(arrowPath);
437  }
438  }
439  return path;
440 }
441 
442 //---------------------------------------------------------------------------------------------------------------------
444 {
445  if (path.size() < 2)
446  {
447  return 0;
448  }
449 
450  QPainterPath splinePath;
451  splinePath.moveTo(path.at(0));
452  for (qint32 i = 1; i < path.count(); ++i)
453  {
454  splinePath.lineTo(path.at(i));
455  }
456  return splinePath.length();
457 }
458 
459 //---------------------------------------------------------------------------------------------------------------------
460 /*
461  * @brief Gets first point in a curve.
462  * @return QPointF
463  */
465 {
466  const QVector<QPointF> points = getPoints();
467  return points.at(0);
468 }
469 
470 //---------------------------------------------------------------------------------------------------------------------
471 /*
472  * @brief Gets last point in a curve.
473  * @return QPointF
474  */
476 {
477  const QVector<QPointF> points = getPoints();
478  return points.at(points.count() - 1);
479 }
QPointF getLastPoint()
QString getLineWeight() const
getLineWeight return weight of the lines
void SetDuplicate(quint32 number)
virtual QVector< DirectionArrow > DirectionArrows() const
virtual ~VAbstractCurve() Q_DECL_OVERRIDE
virtual QVector< QPointF > IntersectLine(const QLineF &line) const
IntersectLine return list of points for real intersection with line.
virtual QVector< QPointF > getPoints() const =0
static qreal PathLength(const QVector< QPointF > &path)
void SetPenStyle(const QString &penStyle)
VAbstractCurve & operator=(const VAbstractCurve &curve)
VAbstractCurve(const GOType &type, const quint32 &idObject=null_id, const Draw &mode=Draw::Calculation)
virtual void CreateName()=0
void setLineColor(const QString &color)
virtual bool IsIntersectLine(const QLineF &line) const
void setLineWeight(const QString &lineWeight)
setLineWeight set weight of the lines
QString GetPenStyle() const
static QVector< QPointF > ToEnd(const QVector< QPointF > &points, const QPointF &end, bool *ok=nullptr)
quint32 GetDuplicate() const
static QVector< QPointF > FromBegin(const QVector< QPointF > &points, const QPointF &begin, bool *ok=nullptr)
void Swap(VAbstractCurve &curve) Q_DECL_NOTHROW
QSharedDataPointer< VAbstractCurveData > d
virtual QPainterPath GetPath() const
static const qreal lengthCurveDirectionArrow
QString getLineColor() const
qreal GetLengthByPoint(const QPointF &point) const
static bool isPointOnCurve(const QVector< QPointF > &points, const QPointF &p)
static QVector< QPointF > CurveIntersectLine(const QVector< QPointF > &points, const QLineF &line)
static QPainterPath ShowDirection(const QVector< DirectionArrow > &arrows, qreal width)
virtual qreal GetLength() const =0
QPointF getFirstPoint()
static QVector< QPointF > GetSegmentPoints(const QVector< QPointF > &points, const QPointF &begin, const QPointF &end, bool reverse=false)
The VGObject class keep information graphical objects.
Definition: vgobject.h:74
static bool IsPointOnLineSegment(const QPointF &t, const QPointF &p1, const QPointF &p2)
IsPointOnLineSegment Check if the point is on the line segment.
Definition: vgobject.cpp:484
VGObject & operator=(const VGObject &obj)
operator = assignment operator.
Definition: vgobject.cpp:109
static QVector< T > GetReversePoints(const QVector< T > &points)
GetReversePoint return revers container of points.
Definition: vgobject.h:145
void Swap(VGObject &obj) Q_DECL_NOTHROW
Definition: vgobject.cpp:72
QPair< QLineF, QLineF > DirectionArrow
GOType
Definition: vgeometrydef.h:56
Draw
Definition: vgeometrydef.h:55