1 /***************************************************************************
2                          qgstriangle.h
3                          -------------------
4     begin                : January 2017
5     copyright            : (C) 2017 by Loïc Bartoletti
6     email                : lbartoletti at tuxfamily dot org
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef QGSTRIANGLE_H
19 #define QGSTRIANGLE_H
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 #include "qgspolygon.h"
24 #include "qgscircle.h"
25 #include "qgslinestring.h"
26 
27 /**
28  * \ingroup core
29  * \class QgsTriangle
30  * \brief Triangle geometry type.
31  * \since QGIS 3.0
32  */
33 class CORE_EXPORT QgsTriangle : public QgsPolygon
34 {
35   public:
36 
37     /**
38      * Constructor for an empty triangle geometry.
39      */
40     QgsTriangle() SIP_HOLDGIL;
41 
42     /**
43      * Construct a QgsTriangle from three QgsPoint.
44      * \param p1 first point
45      * \param p2 second point
46      * \param p3 third point
47      */
48     QgsTriangle( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3 ) SIP_HOLDGIL;
49 
50     /**
51      * Construct a QgsTriangle from three QgsPointXY.
52      * \param p1 first point
53      * \param p2 second point
54      * \param p3 third point
55      */
56     explicit QgsTriangle( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 ) SIP_HOLDGIL;
57 
58     /**
59      * Construct a QgsTriangle from three QPointF.
60      * \param p1 first point
61      * \param p2 second point
62      * \param p3 third point
63      */
64     explicit QgsTriangle( QPointF p1, QPointF p2, QPointF p3 ) SIP_HOLDGIL;
65 
66     bool operator==( const QgsTriangle &other ) const SIP_HOLDGIL;
67     bool operator!=( const QgsTriangle &other ) const SIP_HOLDGIL;
68 
69     QString geometryType() const override SIP_HOLDGIL;
70     QgsTriangle *clone() const override SIP_FACTORY;
71     void clear() override;
72 
73     bool fromWkb( QgsConstWkbPtr &wkbPtr ) override;
74 
75     bool fromWkt( const QString &wkt ) override;
76 
77     // inherited: QString asWkt( int precision = 17 ) const;
78     // inherited (as a polygon): QDomElement asGML2( QDomDocument &doc, int precision = 17, const QString &ns = "gml" ) const;
79     QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
80 
81     QgsPolygon *surfaceToPolygon() const override SIP_FACTORY;
82 
83     QgsCurvePolygon *toCurveType() const override SIP_FACTORY;
84 
85     //! Inherited method not used. You cannot add an interior ring into a triangle.
86     void addInteriorRing( QgsCurve *ring SIP_TRANSFER ) override;
87 
88     /**
89      * Inherited method not used. You cannot add an interior ring into a triangle.
90      * \note not available in Python bindings
91      */
92     void setInteriorRings( const QVector< QgsCurve *> &rings ) = delete;
93     //! Inherited method not used. You cannot delete or insert a vertex directly. Returns always FALSE.
94     bool deleteVertex( QgsVertexId position ) override;
95     //! Inherited method not used. You cannot delete or insert a vertex directly. Returns always FALSE.
96     bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
97     bool moveVertex( QgsVertexId vId, const QgsPoint &newPos ) override;
98 
99     void setExteriorRing( QgsCurve *ring SIP_TRANSFER ) override;
100 
101     QgsCurve *boundary() const override SIP_FACTORY;
102 
103     // inherited: double pointDistanceToBoundary( double x, double y ) const;
104 
105 
106 #ifdef __clang__
107 #pragma clang diagnostic push
108 #pragma clang diagnostic ignored "-Woverloaded-virtual"
109 #endif
110 
111     /**
112      *  Returns coordinates of a vertex.
113      *  \param atVertex index of the vertex
114      *  \returns Coordinates of the vertex or empty QgsPoint on error (\a atVertex < 0 or > 3).
115      */
116     QgsPoint vertexAt( int atVertex ) const SIP_HOLDGIL;
117 #ifdef __clang__
118 #pragma clang diagnostic pop
119 #endif
120 
121     /**
122      * Returns the three lengths of the triangle.
123      * \returns Lengths of triangle ABC where [AB] is at 0, [BC] is at 1, [CA] is at 2.
124      * An empty list is returned for empty triangle.
125      *
126      * ### Example
127      *
128      * \code{.py}
129      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
130      *   tri.lengths()
131      *   # [5.0, 5.0, 7.0710678118654755]
132      *   QgsTriangle().lengths()
133      *   # []
134      * \endcode
135      */
136     QVector<double> lengths() const SIP_HOLDGIL;
137 
138     /**
139      * Returns the three angles of the triangle.
140      * \returns Angles in radians of triangle ABC where angle BAC is at 0, angle ABC is at 1, angle BCA is at 2.
141      * An empty list is returned for empty triangle.
142      *
143      * ### Example
144      *
145      * \code{.py}
146      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
147      *   [math.degrees(i) for i in tri.angles()]
148      *   # [45.0, 90.0, 45.0]
149      *   QgsTriangle().angles()
150      *   # []
151      * \endcode
152      */
153     QVector<double> angles() const SIP_HOLDGIL;
154 
155     /**
156      * Convenient method checking if the geometry is degenerate (have duplicate or colinear point(s)).
157      * \returns TRUE if the triangle is degenerate or empty, otherwise FALSE.
158      *
159      * ### Example
160      *
161      * \code{.py}
162      *   tri = QgsTriangle()
163      *   tri.isDegenerate()
164      *   # True
165      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
166      *   tri.isDegenerate()
167      *   # False
168      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) )
169      *   tri.isDegenerate()
170      *   # True
171      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 5, 5 ) )
172      *   tri.isDegenerate()
173      *   # True
174      *  \endcode
175      */
176     bool isDegenerate() SIP_HOLDGIL;
177 
178     /**
179      * Is the triangle isocele (two sides with the same length)?
180      * \param lengthTolerance The tolerance to use
181      * \returns TRUE or FALSE. Always FALSE for empty triangle.
182      *
183      * ### Example
184      *
185      * \code{.py}
186      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
187      *   tri.lengths()
188      *   # [5.0, 5.0, 7.0710678118654755]
189      *   tri.isIsocele()
190      *   # True
191      *   # length of [AB] == length of [BC]
192      *   QgsTriangle().isIsocele()
193      *   # False
194      * \endcode
195      */
196     bool isIsocele( double lengthTolerance = 0.0001 ) const SIP_HOLDGIL;
197 
198     /**
199      * Is the triangle equilateral (three sides with the same length)?
200      * \param lengthTolerance The tolerance to use
201      * \returns TRUE or FALSE. Always FALSE for empty triangle.
202      *
203      * ### Example
204      *
205      * \code{.py}
206      *   tri = QgsTriangle( QgsPoint( 10, 10 ), QgsPoint( 16, 10 ), QgsPoint( 13, 15.1962 ) )
207      *   tri.lengths()
208      *   # [6.0, 6.0000412031918575, 6.0000412031918575]
209      *   tri.isEquilateral()
210      *   # True
211      *   # All lengths are close to 6.0
212      *   QgsTriangle().isEquilateral()
213      *   # False
214      * \endcode
215      */
216     bool isEquilateral( double lengthTolerance = 0.0001 ) const SIP_HOLDGIL;
217 
218     /**
219      * Is the triangle right-angled?
220      * \param angleTolerance The tolerance to use
221      * \returns TRUE or FALSE. Always FALSE for empty triangle.
222      *
223      * ### Example
224      *
225      * \code{.py}
226      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
227      *   [math.degrees(i) for i in tri.angles()]
228      *   # [45.0, 90.0, 45.0]
229      *   tri.isRight()
230      *   # True
231      *   # angle of ABC == 90
232      *   QgsTriangle().isRight()
233      *   # False
234      * \endcode
235      */
236     bool isRight( double angleTolerance = 0.0001 ) const SIP_HOLDGIL;
237 
238     /**
239      * Is the triangle scalene (all sides have different lengths)?
240      * \param lengthTolerance The tolerance to use
241      * \returns TRUE or FALSE. Always FALSE for empty triangle.
242      *
243      * ### Example
244      *
245      * \code{.py}
246      *   tri = QgsTriangle( QgsPoint( 7.2825, 4.2368 ), QgsPoint( 13.0058, 3.3218 ), QgsPoint( 9.2145, 6.5242 ) )
247      *   tri.lengths()
248      *   # [5.795980321740233, 4.962793714229921, 2.994131386562721]
249      *   tri.isScalene()
250      *   # True
251      *   # All lengths are different
252      *   QgsTriangle().isScalene()
253      *   # False
254      * \endcode
255      */
256     bool isScalene( double lengthTolerance = 0.0001 ) const SIP_HOLDGIL;
257 
258     /**
259      * An altitude is a segment (defined by a QgsLineString) from a vertex to the opposite side (or, if necessary, to the extension of the opposite side).
260      * \returns Three altitudes from this triangle.
261      * An empty list is returned for empty triangle.
262      *
263      * ### Example
264      *
265      * \code{.py}
266      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
267      *   [alt.asWkt() for alt in tri.altitudes()]
268      *   # ['LineString (0 0, 0 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 5)']
269      *   QgsTriangle().altitudes()
270      *   # []
271      * \endcode
272      */
273     QVector<QgsLineString> altitudes() const SIP_HOLDGIL;
274 
275     /**
276      * A median is a segment (defined by a QgsLineString) from a vertex to the midpoint of the opposite side.
277      * \returns Three medians from this triangle.
278      * An empty list is returned for empty triangle.
279      *
280      * ### Example
281      *
282      * \code{.py}
283      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
284      *   [med.asWkt() for med in tri.medians()]
285      *   # ['LineString (0 0, 2.5 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 2.5)']
286      *   QgsTriangle().medians()
287      *   # []
288      * \endcode
289      */
290     QVector<QgsLineString> medians() const SIP_HOLDGIL;
291 
292     /**
293      * The segment (defined by a QgsLineString) returned bisect the angle of a vertex to the opposite side.
294      * \param lengthTolerance The tolerance to use.
295      * \returns Three angle bisector from this triangle.
296      * An empty list is returned for empty triangle.
297      *
298      * ### Example
299      *
300      * \code{.py}
301      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
302      *   [bis.asWkt() for bis in tri.bisectors()]
303      *   # ['LineString (0 0, 2.07106781186547462 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 2.92893218813452538)']
304      *   QgsTriangle().bisectors()
305      *   # []
306      * \endcode
307      */
308     QVector<QgsLineString> bisectors( double lengthTolerance = 0.0001 ) const SIP_HOLDGIL;
309 
310     /**
311      * Medial (or midpoint) triangle of a triangle ABC is the triangle with vertices at the midpoints of the triangle's sides.
312      * \returns The medial from this triangle.
313      * An empty triangle is returned for empty triangle.
314      *
315      * ### Example
316      *
317      * \code{.py}
318      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
319      *   tri.medial().asWkt()
320      *   # 'Triangle ((0 2.5, 2.5 5, 2.5 2.5, 0 2.5))'
321      *   QgsTriangle().medial().asWkt()
322      *   # 'Triangle ( )'
323      * \endcode
324      */
325     QgsTriangle medial() const SIP_HOLDGIL;
326 
327     /**
328      * An orthocenter is the point of intersection of the altitudes of a triangle.
329      * \param lengthTolerance The tolerance to use
330      * \returns The orthocenter of the triangle.
331      * An empty point is returned for empty triangle.
332      *
333      * ### Example
334      *
335      * \code{.py}
336      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
337      *   tri.orthocenter().asWkt()
338      *   # 'Point (0 5)'
339      *   QgsTriangle().orthocenter().asWkt()
340      *   # 'Point (0 0)'
341      * \endcode
342      */
343     QgsPoint orthocenter( double lengthTolerance = 0.0001 ) const SIP_HOLDGIL;
344 
345     /**
346      * Center of the circumscribed circle of the triangle.
347      * \returns The center of the circumscribed circle of the triangle.
348      * An empty point is returned for empty triangle.
349      *
350      * ### Example
351      *
352      * \code{.py}
353      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
354      *   tri.circumscribedCenter().asWkt()
355      *   # 'Point (2.5 2.5)'
356      *   QgsTriangle().circumscribedCenter().asWkt()
357      *   # 'Point (0 0)'
358      * \endcode
359      */
360     QgsPoint circumscribedCenter() const SIP_HOLDGIL;
361 
362     /**
363      * Radius of the circumscribed circle of the triangle.
364      * \returns The radius of the circumscribed circle of the triangle.
365      * 0.0 is returned for empty triangle.
366      *
367      * ### Example
368      *
369      * \code{.py}
370      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
371      *   tri.circumscribedRadius()
372      *   # 3.5355339059327378
373      *   QgsTriangle().circumscribedRadius()
374      *   # 0.0
375      * \endcode
376      */
377     double circumscribedRadius() const SIP_HOLDGIL;
378 
379     /**
380      * Circumscribed circle of the triangle.
381      * \returns The circumbscribed of the triangle with a QgsCircle.
382      * An empty circle is returned for empty triangle.
383      *
384      * ### Example
385      *
386      * \code{.py}
387      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
388      *   tri.circumscribedCircle()
389      *   # QgsCircle(Point (2.5 2.5), 3.5355339059327378, 0)
390      *   QgsTriangle().circumscribedCircle()
391      *   # QgsCircle()
392      * \endcode
393      */
394     QgsCircle circumscribedCircle() const SIP_HOLDGIL;
395 
396     /**
397      * Center of the inscribed circle of the triangle. Z dimension is
398      * supported and is retrieved from the first 3D point amongst vertices.
399      * \returns The center of the inscribed circle of the triangle.
400      * An empty point is returned for empty triangle.
401      *
402      * ### Example
403      *
404      * \code{.py}
405      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
406      *   tri.inscribedCenter().asWkt()
407      *   # 'Point (1.46446609406726225 3.53553390593273775)'
408      *   QgsTriangle().inscribedCenter().asWkt()
409      *   # 'Point (0 0)'
410      * \endcode
411      */
412     QgsPoint inscribedCenter() const SIP_HOLDGIL;
413 
414     /**
415      * Radius of the inscribed circle of the triangle.
416      * \returns The radius of the inscribed circle of the triangle.
417      * 0.0 is returned for empty triangle.
418      *
419      * ### Example
420      *
421      * \code{.py}
422      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
423      *   tri.inscribedRadius()
424      *   # 1.4644660940672622
425      *   QgsTriangle().inscribedRadius()
426      *   # 0.0
427      * \endcode
428      */
429     double inscribedRadius() const SIP_HOLDGIL;
430 
431     /**
432      * Inscribed circle of the triangle.
433      * \returns The inscribed of the triangle with a QgsCircle.
434      * An empty circle is returned for empty triangle.
435      *
436      * ### Example
437      *
438      * \code{.py}
439      *   tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
440      *   tri.inscribedCircle()
441      *   # QgsCircle(Point (1.46446609406726225 3.53553390593273775), 1.4644660940672622, 0)
442      *   QgsTriangle().inscribedCircle()
443      *   # QgsCircle()
444      * \endcode
445      */
446     QgsCircle inscribedCircle() const SIP_HOLDGIL;
447 
448 #ifndef SIP_RUN
449 
450     /**
451      * Cast the \a geom to a QgsTriangle.
452      * Should be used by qgsgeometry_cast<QgsTriangle *>( geometry ).
453      *
454      * \note Not available in Python. Objects will be automatically be converted to the appropriate target type.
455      * \since QGIS 3.0
456      */
cast(const QgsAbstractGeometry * geom)457     inline static const QgsTriangle *cast( const QgsAbstractGeometry *geom )
458     {
459       if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::Triangle )
460         return static_cast<const QgsTriangle *>( geom );
461       return nullptr;
462     }
463 #endif
464 
465     QgsTriangle *createEmptyWithSameType() const override SIP_FACTORY;
466 
467 
468 };
469 #endif // QGSTRIANGLE_H
470