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 &center, 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