1 /*
2  *   libpal - Automated Placement of Labels Library
3  *
4  *   Copyright (C) 2008 Maxence Laurent, MIS-TIC, HEIG-VD
5  *                      University of Applied Sciences, Western Switzerland
6  *                      http://www.hes-so.ch
7  *
8  *   Contact:
9  *      maxence.laurent <at> heig-vd <dot> ch
10  *    or
11  *      eric.taillard <at> heig-vd <dot> ch
12  *
13  * This file is part of libpal.
14  *
15  * libpal is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * libpal is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with libpal.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 
30 #ifndef POINTSET_H
31 #define POINTSET_H
32 
33 #define SIP_NO_FILE
34 
35 
36 #include <cfloat>
37 #include <cmath>
38 #include <QLinkedList>
39 #include <geos_c.h>
40 #include <memory>
41 #include <vector>
42 
43 #include "qgis_core.h"
44 #include "qgsrectangle.h"
45 
46 namespace pal
47 {
48 
49   class Pal;
50   class Projection;
51   class LabelPosition;
52 
53   class PointSet;
54 
55   /**
56    * Represents the minimum area, oriented bounding box surrounding a convex hull.
57    */
58   struct OrientedConvexHullBoundingBox
59   {
60     double x[4];
61     double y[4];
62 
63     double alpha;
64 
65     double width;
66     double length;
67   };
68 
69   /**
70    * \class pal::PointSet
71    * \brief The underlying raw pal geometry class.
72    * \note not available in Python bindings
73    * \ingroup core
74    */
75   class CORE_EXPORT PointSet
76   {
77       friend class FeaturePart;
78       friend class LabelPosition;
79       friend class CostCalculator;
80       friend class PolygonCostCalculator;
81       friend class Layer;
82 
83     public:
84       PointSet();
85       PointSet( int nbPoints, double *x, double *y );
86       virtual ~PointSet();
87 
88       /**
89        * Does... something completely inscrutable.
90        */
91       std::unique_ptr< PointSet > extractShape( int nbPtSh, int imin, int imax, int fps, int fpe, double fptx, double fpty );
92 
93       /**
94        * Returns a copy of the point set.
95        */
96       std::unique_ptr< PointSet > clone() const;
97 
98       /**
99        * Tests whether point set contains a specified point.
100        * \param x x-coordinate of point
101        * \param y y-coordinate of point
102        * \returns TRUE if point set contains a specified point
103        */
104       bool containsPoint( double x, double y ) const;
105 
106       /**
107        * Tests whether a possible label candidate will fit completely within the shape.
108        * \param x x-coordinate of label candidate
109        * \param y y-coordinate of label candidate
110        * \param width label width
111        * \param height label height
112        * \param alpha label angle
113        * \returns TRUE if point set completely contains candidate label
114        */
115       bool containsLabelCandidate( double x, double y, double width, double height, double alpha = 0 ) const;
116 
117       /**
118        * Computes an oriented bounding box for the shape's convex hull.
119        */
120       OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox( bool &ok );
121 
122       /**
123        * Split a concave shape into several convex shapes.
124        */
125       static void splitPolygons( QLinkedList<PointSet *> &inputShapes,
126                                  QLinkedList<PointSet *> &outputShapes,
127                                  double xrm, double yrm );
128 
129       /**
130        * Extends linestrings by the specified amount at the start and end of the line,
131        * by extending the existing lines following the same direction as the original line
132        * start or end.
133        *
134        * The \a smoothDistance argument specifies the distance over which to smooth the direction
135        * of the line at its start and end points.
136        */
137       void extendLineByDistance( double startDistance, double endDistance, double smoothDistance );
138 
139       /**
140        * Returns the squared minimum distance between the point set geometry and the point (px,py)
141        * Optionally, the nearest point is stored in (rx,ry).
142        * \param px x coordinate of the point
143        * \param py y coordinate of the points
144        * \param rx pointer to x coorinates of the nearest point (can be NULL)
145        * \param ry pointer to y coorinates of the nearest point (can be NULL)
146        * \returns minimum distance
147        */
148       double minDistanceToPoint( double px, double py, double *rx = nullptr, double *ry = nullptr ) const;
149 
150       void getCentroid( double &px, double &py, bool forceInside = false ) const;
151 
getGeosType()152       int getGeosType() const { return type; }
153 
154       /**
155        * Returns the point set bounding box.
156        */
boundingBox()157       QgsRectangle boundingBox() const
158       {
159         return QgsRectangle( xmin, ymin, xmax, ymax );
160       }
161 
162       /**
163        * Returns TRUE if the bounding box of this pointset intersects the bounding box
164        * of another pointset.
165        */
166       bool boundingBoxIntersects( const PointSet *other ) const;
167 
168       //! Returns NULLPTR if this isn't a hole. Otherwise returns pointer to parent pointset.
getHoleOf()169       PointSet *getHoleOf() const { return holeOf; }
170 
getNumPoints()171       int getNumPoints() const { return nbPoints; }
172 
173       /**
174        * Gets a point a set distance along a line geometry.
175        * \param d array of distances between points
176        * \param ad cumulative total distance from pt0 to each point (ad0 = pt0->pt0)
177        * \param dl distance to traverse along line
178        * \param px final x coord on line
179        * \param py final y coord on line
180       */
181       void getPointByDistance( double *d, double *ad, double dl, double *px, double *py );
182 
183       /**
184        * Returns the point set's GEOS geometry.
185       */
186       const GEOSGeometry *geos() const;
187 
188       /**
189        * Returns length of line geometry.
190        */
191       double length() const;
192 
193       /**
194        * Returns area of polygon geometry.
195        */
196       double area() const;
197 
198       /**
199        * Returns TRUE if pointset is closed.
200        */
201       bool isClosed() const;
202 
203       int nbPoints;
204       std::vector< double > x;
205       std::vector< double > y;   // points order is counterclockwise
206 
207     protected:
208       mutable GEOSGeometry *mGeos = nullptr;
209       mutable bool mOwnsGeom = false;
210 
211       int *cHull = nullptr;
212       int cHullSize = 0;
213 
214       int type;
215 
216       PointSet *holeOf = nullptr;
217       PointSet *parent = nullptr;
218 
219       mutable double mArea = -1;
220       mutable double mLength = -1;
221 
222 
223       PointSet( double x, double y );
224 
225       PointSet( const PointSet &ps );
226 
227       void deleteCoords();
228       void createGeosGeom() const;
229       const GEOSPreparedGeometry *preparedGeom() const;
230       void invalidateGeos();
231 
232       double xmin = std::numeric_limits<double>::max();
233       double xmax = std::numeric_limits<double>::lowest();
234       double ymin = std::numeric_limits<double>::max();
235       double ymax = std::numeric_limits<double>::lowest();
236 
237     private:
238 
239       mutable const GEOSPreparedGeometry *mPreparedGeom = nullptr;
240 
241       PointSet &operator= ( const PointSet & ) = delete;
242 
243   };
244 
245 } // namespace pal
246 
247 #endif
248 
249