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