1 /*************************************************************************** 2 qgsquadrilateral.h 3 ------------------- 4 begin : November 2018 5 copyright : (C) 2018 by Loïc Bartoletti 6 email : loic dot bartoletti at oslandia dot com 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 QGSQUADRILATERAL_H 19 #define QGSQUADRILATERAL_H 20 21 22 #include "qgis_core.h" 23 #include "qgspoint.h" 24 #include "qgspolygon.h" 25 #include "qgslinestring.h" 26 27 /** 28 * \ingroup core 29 * \class QgsQuadrilateral 30 * \brief Quadrilateral geometry type. 31 * 32 * A quadrilateral is a polygon with four edges (or sides) and four vertices or corners. 33 * This class allows the creation of simple quadrilateral (which does not self-intersect). 34 * \since QGIS 3.6 35 */ 36 class CORE_EXPORT QgsQuadrilateral 37 { 38 public: 39 40 /** 41 * Constructor for an empty quadrilateral geometry. 42 */ 43 QgsQuadrilateral() SIP_HOLDGIL; 44 45 /** 46 * Construct a QgsQuadrilateral from four QgsPoint. 47 * \param p1 first point 48 * \param p2 second point 49 * \param p3 third point 50 * \param p4 fourth point 51 * \see setPoints 52 */ 53 QgsQuadrilateral( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 ) SIP_HOLDGIL; 54 55 /** 56 * Construct a QgsQuadrilateral from four QgsPointXY. 57 * \param p1 first point 58 * \param p2 second point 59 * \param p3 third point 60 * \param p4 fourth point 61 * \see setPoints 62 */ 63 explicit QgsQuadrilateral( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, const QgsPointXY &p4 ) SIP_HOLDGIL; 64 65 66 /** 67 * A quadrilateral can be constructed from 3 points where the second distance can be determined by the third point. 68 * 69 */ 70 enum ConstructionOption 71 { 72 Distance, //!< Second distance is equal to the distance between 2nd and 3rd point 73 Projected, //!< Second distance is equal to the distance of the perpendicular projection of the 3rd point on the segment or its extension. 74 }; 75 76 /** 77 * Construct a QgsQuadrilateral as a Rectangle from 3 points. 78 * In the case where one of the points is of type PointZ. The other points 79 * will also be of type Z, even if they are of type Point. In addition, 80 * the z used will be the one of the first point with a Z. 81 * This ensures consistency in point types and the ability to export to a 82 * Polygon or LineString. 83 * M is taken from point \a p1. 84 * \param p1 first point 85 * \param p2 second point 86 * \param p3 third point 87 * \param mode Construction mode to construct the rectangle from 3 points 88 * \see ConstructionOption 89 */ 90 static QgsQuadrilateral rectangleFrom3Points( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, ConstructionOption mode ) SIP_HOLDGIL; 91 92 /** 93 * Construct a QgsQuadrilateral as a rectangle from an extent, defined by 94 * two opposite corner points. 95 * Z and M are taken from point \a p1. 96 * QgsQuadrilateral will have the same dimension as \a p1 dimension. 97 * \param p1 first point 98 * \param p2 second point 99 */ 100 static QgsQuadrilateral rectangleFromExtent( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL; 101 102 #ifndef SIP_RUN 103 104 /** 105 * Alias for rectangleFromDiagonal 106 */ 107 static constexpr auto &rectangleFromDiagonal = rectangleFromExtent; 108 #endif 109 110 /** 111 * Construct a QgsQuadrilateral as a square from a diagonal. 112 * Z and M are taken from point \a p1. 113 * QgsQuadrilateral will have the same dimension as \a p1 dimension. 114 * \param p1 first point 115 * \param p2 second point 116 */ 117 static QgsQuadrilateral squareFromDiagonal( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL; 118 119 /** 120 * Construct a QgsQuadrilateral as a rectangle from center point \a center 121 * and another point \a point. 122 * Z and M are taken from point \a p1. 123 * QgsQuadrilateral will have the same dimension as \a center dimension. 124 * \param center center point 125 * \param point corner point 126 */ 127 static QgsQuadrilateral rectangleFromCenterPoint( const QgsPoint ¢er, const QgsPoint &point ) SIP_HOLDGIL; 128 129 /** 130 * Construct a QgsQuadrilateral as a rectangle from a QgsRectangle. 131 * \param rectangle rectangle 132 */ 133 static QgsQuadrilateral fromRectangle( const QgsRectangle &rectangle ) SIP_HOLDGIL; 134 135 // TODO: 136 // Rhombus 137 138 /** 139 * Compares two QgsQuadrilateral, allowing specification of the maximum allowable difference between points. 140 * \param other the QgsQuadrilateral to compare 141 * \param epsilon the maximum difference allowed / tolerance 142 */ 143 bool equals( const QgsQuadrilateral &other, double epsilon = 4 * std::numeric_limits<double>::epsilon() ) const SIP_HOLDGIL; 144 bool operator==( const QgsQuadrilateral &other ) const SIP_HOLDGIL; 145 bool operator!=( const QgsQuadrilateral &other ) const SIP_HOLDGIL; 146 147 /** 148 * Convenient method to determine if a QgsQuadrilateral is valid. 149 * A QgsQuadrilateral must be simple (not self-intersecting) and 150 * cannot have collinear points. 151 */ 152 bool isValid() const SIP_HOLDGIL; 153 154 /** 155 * Simple enumeration to ensure indices in setPoint 156 */ 157 enum Point 158 { 159 Point1, 160 Point2, 161 Point3, 162 Point4, 163 }; 164 165 /** 166 * Sets the point \a newPoint at the \a index. 167 * Returns FALSE if the QgsQuadrilateral is not valid. 168 * \see Point 169 */ 170 bool setPoint( const QgsPoint &newPoint, Point index ) SIP_HOLDGIL; 171 172 /** 173 * Set all points 174 * Returns FALSE if the QgsQuadrilateral is not valid: 175 * 176 * - The points do not have the same type 177 * - The quadrilateral would have auto intersections 178 * - The quadrilateral has double points 179 * - The quadrilateral has collinear points 180 */ 181 bool setPoints( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 ) SIP_HOLDGIL; 182 183 /** 184 * Returns a list including the vertices of the quadrilateral. 185 */ 186 QgsPointSequence points() const; 187 188 /** 189 * Returns the quadrilateral as a new polygon. Ownership is transferred to the caller. 190 */ 191 QgsPolygon *toPolygon( bool force2D = false ) const SIP_FACTORY; 192 193 /** 194 * Returns the quadrilateral as a new linestring. Ownership is transferred to the caller. 195 */ 196 QgsLineString *toLineString( bool force2D = false ) const SIP_FACTORY; 197 198 /** 199 * Returns a string representation of the quadrilateral. 200 * Members will be truncated to the specified precision. 201 */ 202 QString toString( int pointPrecision = 17 ) const; 203 204 /** 205 * Returns the area of the quadrilateral, or 0 if the quadrilateral is empty. 206 */ 207 double area() const SIP_HOLDGIL; 208 209 /** 210 * Returns the perimeter of the quadrilateral, or 0 if the quadrilateral is empty. 211 */ 212 double perimeter() const SIP_HOLDGIL; 213 #ifdef SIP_RUN 214 SIP_PYOBJECT __repr__(); 215 % MethodCode 216 QString str = QStringLiteral( "<QgsQuadrilateral: %1>" ).arg( sipCpp->toString() ); 217 sipRes = PyUnicode_FromString( str.toUtf8().constData() ); 218 % End 219 #endif 220 private: 221 QgsPoint mPoint1, mPoint2, mPoint3, mPoint4; 222 }; 223 224 #endif // QGSQUADRILATERAL_H 225