1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qline.h"
41
42#include "qdebug.h"
43#include "qdatastream.h"
44#include "qmath.h"
45#include <private/qnumeric_p.h>
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \class QLine
51 \inmodule QtCore
52 \ingroup painting
53
54 \brief The QLine class provides a two-dimensional vector using
55 integer precision.
56
57 A QLine describes a finite length line (or a line segment) on a
58 two-dimensional surface. The start and end points of the line are
59 specified using integer point accuracy for coordinates. Use the
60 QLineF constructor to retrieve a floating point copy.
61
62 \table
63 \row
64 \li \inlineimage qline-point.png
65 \li \inlineimage qline-coordinates.png
66 \endtable
67
68 The positions of the line's start and end points can be retrieved
69 using the p1(), x1(), y1(), p2(), x2(), and y2() functions. The
70 dx() and dy() functions return the horizontal and vertical
71 components of the line. Use isNull() to determine whether the
72 QLine represents a valid line or a null line.
73
74 Finally, the line can be translated a given offset using the
75 translate() function.
76
77 \sa QLineF, QPolygon, QRect
78*/
79
80/*!
81 \fn QLine::QLine()
82
83 Constructs a null line.
84*/
85
86/*!
87 \fn QLine::QLine(const QPoint &p1, const QPoint &p2)
88
89 Constructs a line object that represents the line between \a p1 and
90 \a p2.
91*/
92
93/*!
94 \fn QLine::QLine(int x1, int y1, int x2, int y2)
95
96 Constructs a line object that represents the line between (\a x1, \a y1) and
97 (\a x2, \a y2).
98*/
99
100/*!
101 \fn bool QLine::isNull() const
102
103 Returns \c true if the line does not have distinct start and end points;
104 otherwise returns \c false.
105*/
106
107/*!
108 \fn QPoint QLine::p1() const
109
110 Returns the line's start point.
111
112 \sa x1(), y1(), p2()
113*/
114
115/*!
116 \fn QPoint QLine::p2() const
117
118 Returns the line's end point.
119
120 \sa x2(), y2(), p1()
121*/
122
123/*!
124 \fn int QLine::x1() const
125
126 Returns the x-coordinate of the line's start point.
127
128 \sa p1()
129*/
130
131/*!
132 \fn int QLine::y1() const
133
134 Returns the y-coordinate of the line's start point.
135
136 \sa p1()
137*/
138
139/*!
140 \fn int QLine::x2() const
141
142 Returns the x-coordinate of the line's end point.
143
144 \sa p2()
145*/
146
147/*!
148 \fn int QLine::y2() const
149
150 Returns the y-coordinate of the line's end point.
151
152 \sa p2()
153*/
154
155/*!
156 \fn int QLine::dx() const
157
158 Returns the horizontal component of the line's vector.
159
160 \sa dy()
161*/
162
163/*!
164 \fn int QLine::dy() const
165
166 Returns the vertical component of the line's vector.
167
168 \sa dx()
169*/
170
171/*!
172 \fn bool QLine::operator!=(const QLine &line) const
173
174 Returns \c true if the given \a line is not the same as \e this line.
175
176 A line is different from another line if any of their start or
177 end points differ, or the internal order of the points is different.
178*/
179
180/*!
181 \fn bool QLine::operator==(const QLine &line) const
182
183 Returns \c true if the given \a line is the same as \e this line.
184
185 A line is identical to another line if the start and end points
186 are identical, and the internal order of the points is the same.
187*/
188
189/*!
190 \fn void QLine::translate(const QPoint &offset)
191
192 Translates this line by the given \a offset.
193*/
194
195/*!
196 \fn void QLine::translate(int dx, int dy)
197 \overload
198
199 Translates this line the distance specified by \a dx and \a dy.
200*/
201
202/*!
203 \fn QLine QLine::translated(const QPoint &offset) const
204
205 \since 4.4
206
207 Returns this line translated by the given \a offset.
208*/
209
210/*!
211 \fn QLine QLine::translated(int dx, int dy) const
212 \overload
213 \since 4.4
214
215 Returns this line translated the distance specified by \a dx and \a dy.
216*/
217
218/*!
219 \fn QPoint QLine::center() const
220
221 \since 5.8
222
223 Returns the center point of this line. This is equivalent to
224 (p1() + p2()) / 2, except it will never overflow.
225*/
226
227/*!
228 \fn void QLine::setP1(const QPoint &p1)
229 \since 4.4
230
231 Sets the starting point of this line to \a p1.
232
233 \sa setP2(), p1()
234*/
235
236
237/*!
238 \fn void QLine::setP2(const QPoint &p2)
239 \since 4.4
240
241 Sets the end point of this line to \a p2.
242
243 \sa setP1(), p2()
244*/
245
246
247/*!
248 \fn void QLine::setPoints(const QPoint &p1, const QPoint &p2)
249 \since 4.4
250
251 Sets the start point of this line to \a p1 and the end point of this line to \a p2.
252
253 \sa setP1(), setP2(), p1(), p2()
254*/
255
256
257/*!
258 \fn void QLine::setLine(int x1, int y1, int x2, int y2)
259 \since 4.4
260
261 Sets this line to the start in \a x1, \a y1 and end in \a x2, \a y2.
262
263 \sa setP1(), setP2(), p1(), p2()
264*/
265
266
267
268#ifndef QT_NO_DEBUG_STREAM
269QDebug operator<<(QDebug dbg, const QLine &p)
270{
271 QDebugStateSaver saver(dbg);
272 dbg.nospace() << "QLine(" << p.p1() << ',' << p.p2() << ')';
273 return dbg;
274}
275#endif
276
277#ifndef QT_NO_DATASTREAM
278/*!
279 \relates QLine
280
281 Writes the given \a line to the given \a stream and returns a
282 reference to the stream.
283
284 \sa {Serializing Qt Data Types}
285*/
286
287QDataStream &operator<<(QDataStream &stream, const QLine &line)
288{
289 stream << line.p1() << line.p2();
290 return stream;
291}
292
293/*!
294 \relates QLine
295
296 Reads a line from the given \a stream into the given \a line and
297 returns a reference to the stream.
298
299 \sa {Serializing Qt Data Types}
300*/
301
302QDataStream &operator>>(QDataStream &stream, QLine &line)
303{
304 QPoint p1, p2;
305 stream >> p1;
306 stream >> p2;
307 line = QLine(p1, p2);
308
309 return stream;
310}
311
312#endif // QT_NO_DATASTREAM
313
314/*!
315 \class QLineF
316 \inmodule QtCore
317 \ingroup painting
318
319 \brief The QLineF class provides a two-dimensional vector using
320 floating point precision.
321
322 A QLineF describes a finite length line (or line segment) on a
323 two-dimensional surface. QLineF defines the start and end points
324 of the line using floating point accuracy for coordinates. Use
325 the toLine() function to retrieve an integer based copy of this
326 line.
327
328 \table
329 \row
330 \li \inlineimage qline-point.png
331 \li \inlineimage qline-coordinates.png
332 \endtable
333
334 The positions of the line's start and end points can be retrieved
335 using the p1(), x1(), y1(), p2(), x2(), and y2() functions. The
336 dx() and dy() functions return the horizontal and vertical
337 components of the line, respectively.
338
339 The line's length can be retrieved using the length() function,
340 and altered using the setLength() function. Similarly, angle()
341 and setAngle() are respectively used for retrieving and altering
342 the angle of the line. Use the isNull()
343 function to determine whether the QLineF represents a valid line
344 or a null line.
345
346 The intersects() function determines the IntersectionType for this
347 line and a given line, while the angleTo() function returns the
348 angle between the lines. In addition, the unitVector() function
349 returns a line that has the same starting point as this line, but
350 with a length of only 1, while the normalVector() function returns
351 a line that is perpendicular to this line with the same starting
352 point and length.
353
354 Finally, the line can be translated a given offset using the
355 translate() function, and can be traversed using the pointAt()
356 function.
357
358 \section1 Constraints
359
360 QLine is limited to the minimum and maximum values for the
361 \c int type. Operations on a QLine that could potentially result
362 in values outside this range will result in undefined behavior.
363
364 \sa QLine, QPolygonF, QRectF
365*/
366
367/*!
368 \typealias QLineF::IntersectType
369 \obsolete Use QLineF::IntersectionType instead.
370*/
371
372/*!
373 \enum QLineF::IntersectionType
374
375 Describes the intersection between two lines.
376
377 \table
378 \row
379 \li \inlineimage qlinef-unbounded.png
380 \li \inlineimage qlinef-bounded.png
381 \row
382 \li QLineF::UnboundedIntersection
383 \li QLineF::BoundedIntersection
384 \endtable
385
386 \value NoIntersection Indicates that the lines do not intersect;
387 i.e. they are parallel.
388
389 \value UnboundedIntersection The two lines intersect, but not
390 within the range defined by their lengths. This will be the case
391 if the lines are not parallel. intersect() will also return this
392 value if the intersect point is within the start and end point of
393 only one of the lines.
394
395 \value BoundedIntersection The two lines intersect with each other
396 within the start and end points of each line.
397
398 \sa intersects()
399*/
400
401/*!
402 \fn QLineF::QLineF()
403
404 Constructs a null line.
405*/
406
407/*!
408 \fn QLineF::QLineF(const QPointF &p1, const QPointF &p2)
409
410 Constructs a line object that represents the line between \a p1 and
411 \a p2.
412*/
413
414/*!
415 \fn QLineF::QLineF(qreal x1, qreal y1, qreal x2, qreal y2)
416
417 Constructs a line object that represents the line between (\a x1, \a y1) and
418 (\a x2, \a y2).
419*/
420
421/*!
422 \fn QLineF::QLineF(const QLine &line)
423
424 Construct a QLineF object from the given integer-based \a line.
425
426 \sa toLine()
427*/
428
429/*!
430 \fn bool QLineF::isNull() const
431
432 Returns \c true if the line does not have distinct start and end points;
433 otherwise returns \c false. The start and end points are considered distinct
434 if qFuzzyCompare() can distinguish them in at least one coordinate.
435
436 \note Due to the use of fuzzy comparison, isNull() may return \c true for
437 lines whose length() is not zero.
438
439 \sa qFuzzyCompare(), length()
440*/
441
442/*!
443 \fn QPointF QLineF::p1() const
444
445 Returns the line's start point.
446
447 \sa x1(), y1(), p2()
448*/
449
450/*!
451 \fn QPointF QLineF::p2() const
452
453 Returns the line's end point.
454
455 \sa x2(), y2(), p1()
456*/
457
458/*!
459 \fn QLine QLineF::toLine() const
460
461 Returns an integer based copy of this line.
462
463 Note that the returned line's start and end points are rounded to
464 the nearest integer.
465
466 \sa QLineF()
467*/
468/*!
469 \fn qreal QLineF::x1() const
470
471 Returns the x-coordinate of the line's start point.
472
473 \sa p1()
474*/
475
476/*!
477 \fn qreal QLineF::y1() const
478
479 Returns the y-coordinate of the line's start point.
480
481 \sa p1()
482*/
483
484/*!
485 \fn qreal QLineF::x2() const
486
487 Returns the x-coordinate of the line's end point.
488
489 \sa p2()
490*/
491
492/*!
493 \fn qreal QLineF::y2() const
494
495 Returns the y-coordinate of the line's end point.
496
497 \sa p2()
498*/
499
500/*!
501 \fn qreal QLineF::dx() const
502
503 Returns the horizontal component of the line's vector.
504
505 \sa dy(), pointAt()
506*/
507
508/*!
509 \fn qreal QLineF::dy() const
510
511 Returns the vertical component of the line's vector.
512
513 \sa dx(), pointAt()
514*/
515
516/*!
517 \fn void QLineF::setLength(qreal length)
518
519 Sets the length of the line to the given \a length. QLineF will
520 move the end point - p2() - of the line to give the line its new length.
521
522 A null line will not be rescaled. For non-null lines with very short lengths
523 (represented by denormal floating-point values), results may be imprecise.
524
525 \sa length(), isNull(), unitVector()
526*/
527
528/*!
529 \fn QLineF QLineF::normalVector() const
530
531 Returns a line that is perpendicular to this line with the same starting
532 point and length.
533
534 \image qlinef-normalvector.png
535
536 \sa unitVector()
537*/
538
539/*!
540 \fn bool QLineF::operator!=(const QLineF &line) const
541
542 Returns \c true if the given \a line is not the same as \e this line.
543
544 A line is different from another line if their start or end points
545 differ, or the internal order of the points is different.
546*/
547
548/*!
549 \fn bool QLineF::operator==(const QLineF &line) const
550
551 Returns \c true if the given \a line is the same as this line.
552
553 A line is identical to another line if the start and end points
554 are identical, and the internal order of the points is the same.
555*/
556
557/*!
558 \fn qreal QLineF::pointAt(qreal t) const
559
560 Returns the point at the parameterized position specified by \a
561 t. The function returns the line's start point if t = 0, and its end
562 point if t = 1.
563
564 \sa dx(), dy()
565*/
566
567/*!
568 Returns the length of the line.
569
570 \sa setLength(), isNull()
571*/
572qreal QLineF::length() const
573{
574 using std::hypot;
575 return hypot(dx(), dy());
576}
577
578/*!
579 \since 4.4
580
581 Returns the angle of the line in degrees.
582
583 The return value will be in the range of values from 0.0 up to but not
584 including 360.0. The angles are measured counter-clockwise from a point
585 on the x-axis to the right of the origin (x > 0).
586
587 \sa setAngle()
588*/
589qreal QLineF::angle() const
590{
591 const qreal dx = pt2.x() - pt1.x();
592 const qreal dy = pt2.y() - pt1.y();
593
594 const qreal theta = qRadiansToDegrees(qAtan2(-dy, dx));
595
596 const qreal theta_normalized = theta < 0 ? theta + 360 : theta;
597
598 if (qFuzzyCompare(theta_normalized, qreal(360)))
599 return qreal(0);
600 else
601 return theta_normalized;
602}
603
604/*!
605 \since 4.4
606
607 Sets the angle of the line to the given \a angle (in degrees).
608 This will change the position of the second point of the line such that
609 the line has the given angle.
610
611 Positive values for the angles mean counter-clockwise while negative values
612 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
613
614 \sa angle()
615*/
616void QLineF::setAngle(qreal angle)
617{
618 const qreal angleR = qDegreesToRadians(angle);
619 const qreal l = length();
620
621 const qreal dx = qCos(angleR) * l;
622 const qreal dy = -qSin(angleR) * l;
623
624 pt2.rx() = pt1.x() + dx;
625 pt2.ry() = pt1.y() + dy;
626}
627
628/*!
629 \since 4.4
630
631 Returns a QLineF with the given \a length and \a angle.
632
633 The first point of the line will be on the origin.
634
635 Positive values for the angles mean counter-clockwise while negative values
636 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
637*/
638QLineF QLineF::fromPolar(qreal length, qreal angle)
639{
640 const qreal angleR = qDegreesToRadians(angle);
641 return QLineF(0, 0, qCos(angleR) * length, -qSin(angleR) * length);
642}
643
644/*!
645 Returns the unit vector for this line, i.e a line starting at the
646 same point as \e this line with a length of 1.0, provided the line
647 is non-null.
648
649 \sa normalVector(), setLength()
650*/
651QLineF QLineF::unitVector() const
652{
653 qreal x = dx();
654 qreal y = dy();
655 using std::hypot;
656 qreal len = hypot(x, y);
657
658 QLineF f(p1(), QPointF(pt1.x() + x/len, pt1.y() + y/len));
659
660#ifndef QT_NO_DEBUG
661 if (qAbs(f.length() - 1) >= 0.001)
662 qWarning("QLine::unitVector: New line does not have unit length");
663#endif
664
665 return f;
666}
667
668/*!
669 \fn QLineF::IntersectionType QLineF::intersects(const QLineF &line, QPointF *intersectionPoint) const
670 \since 5.14
671
672 Returns a value indicating whether or not \e this line intersects
673 with the given \a line.
674
675 The actual intersection point is extracted to \a intersectionPoint
676 (if the pointer is valid). If the lines are parallel, the
677 intersection point is undefined.
678*/
679QLineF::IntersectionType QLineF::intersects(const QLineF &l, QPointF *intersectionPoint) const
680{
681 // ipmlementation is based on Graphics Gems III's "Faster Line Segment Intersection"
682 const QPointF a = pt2 - pt1;
683 const QPointF b = l.pt1 - l.pt2;
684 const QPointF c = pt1 - l.pt1;
685
686 const qreal denominator = a.y() * b.x() - a.x() * b.y();
687 if (denominator == 0 || !qt_is_finite(denominator))
688 return NoIntersection;
689
690 const qreal reciprocal = 1 / denominator;
691 const qreal na = (b.y() * c.x() - b.x() * c.y()) * reciprocal;
692 if (intersectionPoint)
693 *intersectionPoint = pt1 + a * na;
694
695 if (na < 0 || na > 1)
696 return UnboundedIntersection;
697
698 const qreal nb = (a.x() * c.y() - a.y() * c.x()) * reciprocal;
699 if (nb < 0 || nb > 1)
700 return UnboundedIntersection;
701
702 return BoundedIntersection;
703}
704
705/*!
706 \fn void QLineF::translate(const QPointF &offset)
707
708 Translates this line by the given \a offset.
709*/
710
711/*!
712 \fn void QLineF::translate(qreal dx, qreal dy)
713 \overload
714
715 Translates this line the distance specified by \a dx and \a dy.
716*/
717
718/*!
719 \fn QLineF QLineF::translated(const QPointF &offset) const
720
721 \since 4.4
722
723 Returns this line translated by the given \a offset.
724*/
725
726/*!
727 \fn QLineF QLineF::translated(qreal dx, qreal dy) const
728 \overload
729 \since 4.4
730
731 Returns this line translated the distance specified by \a dx and \a dy.
732*/
733
734/*!
735 \fn QPointF QLineF::center() const
736
737 \since 5.8
738
739 Returns the center point of this line. This is equivalent to
740 0.5 * p1() + 0.5 * p2().
741*/
742
743/*!
744 \fn void QLineF::setP1(const QPointF &p1)
745 \since 4.4
746
747 Sets the starting point of this line to \a p1.
748
749 \sa setP2(), p1()
750*/
751
752
753/*!
754 \fn void QLineF::setP2(const QPointF &p2)
755 \since 4.4
756
757 Sets the end point of this line to \a p2.
758
759 \sa setP1(), p2()
760*/
761
762
763/*!
764 \fn void QLineF::setPoints(const QPointF &p1, const QPointF &p2)
765 \since 4.4
766
767 Sets the start point of this line to \a p1 and the end point of this line to \a p2.
768
769 \sa setP1(), setP2(), p1(), p2()
770*/
771
772
773/*!
774 \fn void QLineF::setLine(qreal x1, qreal y1, qreal x2, qreal y2)
775 \since 4.4
776
777 Sets this line to the start in \a x1, \a y1 and end in \a x2, \a y2.
778
779 \sa setP1(), setP2(), p1(), p2()
780*/
781
782/*!
783 \fn qreal QLineF::angleTo(const QLineF &line) const
784
785 \since 4.4
786
787 Returns the angle (in degrees) from this line to the given \a
788 line, taking the direction of the lines into account. If the lines
789 do not \l{intersects()}{intersect} within their range, it is the
790 intersection point of the extended lines that serves as origin (see
791 QLineF::UnboundedIntersection).
792
793 The returned value represents the number of degrees you need to add
794 to this line to make it have the same angle as the given \a line,
795 going counter-clockwise.
796
797 \sa intersects()
798*/
799qreal QLineF::angleTo(const QLineF &l) const
800{
801 if (isNull() || l.isNull())
802 return 0;
803
804 const qreal a1 = angle();
805 const qreal a2 = l.angle();
806
807 const qreal delta = a2 - a1;
808 const qreal delta_normalized = delta < 0 ? delta + 360 : delta;
809
810 if (qFuzzyCompare(delta, qreal(360)))
811 return 0;
812 else
813 return delta_normalized;
814}
815
816#ifndef QT_NO_DEBUG_STREAM
817QDebug operator<<(QDebug dbg, const QLineF &p)
818{
819 QDebugStateSaver saver(dbg);
820 dbg.nospace() << "QLineF(" << p.p1() << ',' << p.p2() << ')';
821 return dbg;
822}
823#endif
824
825#ifndef QT_NO_DATASTREAM
826/*!
827 \relates QLineF
828
829 Writes the given \a line to the given \a stream and returns a
830 reference to the stream.
831
832 \sa {Serializing Qt Data Types}
833*/
834
835QDataStream &operator<<(QDataStream &stream, const QLineF &line)
836{
837 stream << line.p1() << line.p2();
838 return stream;
839}
840
841/*!
842 \relates QLineF
843
844 Reads a line from the given \a stream into the given \a line and
845 returns a reference to the stream.
846
847 \sa {Serializing Qt Data Types}
848*/
849
850QDataStream &operator>>(QDataStream &stream, QLineF &line)
851{
852 QPointF start, end;
853 stream >> start;
854 stream >> end;
855 line = QLineF(start, end);
856
857 return stream;
858}
859
860#endif // QT_NO_DATASTREAM
861
862QT_END_NAMESPACE
863