QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
pointset.cpp
Go to the documentation of this file.
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 #include "pointset.h"
31 #include "util.h"
32 #include "geomfunction.h"
33 #include "qgsgeos.h"
34 #include "qgsmessagelog.h"
35 #include "qgsgeometryutils.h"
36 #include <qglobal.h>
37 
38 using namespace pal;
39 
41 {
42  nbPoints = 0;
43  type = -1;
44 }
45 
46 PointSet::PointSet( int nbPoints, double *x, double *y )
47  : nbPoints( nbPoints )
48  , type( GEOS_POLYGON )
49 {
50  this->x.resize( nbPoints );
51  this->y.resize( nbPoints );
52  int i;
53 
54  for ( i = 0; i < nbPoints; i++ )
55  {
56  this->x[i] = x[i];
57  this->y[i] = y[i];
58  }
59 
60 }
61 
62 PointSet::PointSet( double aX, double aY )
63  : type( GEOS_POINT )
64  , xmin( aX )
65  , xmax( aY )
66  , ymin( aX )
67  , ymax( aY )
68 {
69  nbPoints = 1;
70  x.resize( 1 );
71  y.resize( 1 );
72  x[0] = aX;
73  y[0] = aY;
74 }
75 
77  : xmin( ps.xmin )
78  , xmax( ps.xmax )
79  , ymin( ps.ymin )
80  , ymax( ps.ymax )
81 {
82  nbPoints = ps.nbPoints;
83  x = ps.x;
84  y = ps.y;
85 
87 
88  type = ps.type;
89 
90  holeOf = ps.holeOf;
91 
92  if ( ps.mGeos )
93  {
94  mGeos = GEOSGeom_clone_r( QgsGeos::getGEOSHandler(), ps.mGeos );
95  mOwnsGeom = true;
96  }
97 }
98 
100 {
101  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
102 
103  bool needClose = false;
104  if ( type == GEOS_POLYGON && ( !qgsDoubleNear( x[0], x[ nbPoints - 1] ) || !qgsDoubleNear( y[0], y[ nbPoints - 1 ] ) ) )
105  {
106  needClose = true;
107  }
108 
109  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, nbPoints + ( needClose ? 1 : 0 ), 2 );
110  for ( int i = 0; i < nbPoints; ++i )
111  {
112 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
113  GEOSCoordSeq_setXY_r( geosctxt, coord, i, x[i], y[i] );
114 #else
115  GEOSCoordSeq_setX_r( geosctxt, coord, i, x[i] );
116  GEOSCoordSeq_setY_r( geosctxt, coord, i, y[i] );
117 #endif
118  }
119 
120  //close ring if needed
121  if ( needClose )
122  {
123 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
124  GEOSCoordSeq_setXY_r( geosctxt, coord, nbPoints, x[0], y[0] );
125 #else
126  GEOSCoordSeq_setX_r( geosctxt, coord, nbPoints, x[0] );
127  GEOSCoordSeq_setY_r( geosctxt, coord, nbPoints, y[0] );
128 #endif
129  }
130 
131  switch ( type )
132  {
133  case GEOS_POLYGON:
134  mGeos = GEOSGeom_createPolygon_r( geosctxt, GEOSGeom_createLinearRing_r( geosctxt, coord ), nullptr, 0 );
135  break;
136 
137  case GEOS_LINESTRING:
138  mGeos = GEOSGeom_createLineString_r( geosctxt, coord );
139  break;
140 
141  case GEOS_POINT:
142  mGeos = GEOSGeom_createPoint_r( geosctxt, coord );
143  break;
144  }
145 
146  mOwnsGeom = true;
147 }
148 
149 const GEOSPreparedGeometry *PointSet::preparedGeom() const
150 {
151  if ( !mGeos )
152  createGeosGeom();
153 
154  if ( !mPreparedGeom )
155  {
156  mPreparedGeom = GEOSPrepare_r( QgsGeos::getGEOSHandler(), mGeos );
157  }
158  return mPreparedGeom;
159 }
160 
162 {
163  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
164  if ( mOwnsGeom ) // delete old geometry if we own it
165  GEOSGeom_destroy_r( geosctxt, mGeos );
166  mOwnsGeom = false;
167  mGeos = nullptr;
168 
169  if ( mPreparedGeom )
170  {
171  GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
172  mPreparedGeom = nullptr;
173  }
174 
175  if ( mGeosPreparedBoundary )
176  {
177  GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
178  mGeosPreparedBoundary = nullptr;
179  }
180 
181  if ( mMultipartPreparedGeos )
182  {
183  GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
184  mMultipartPreparedGeos = nullptr;
185  }
186  if ( mMultipartGeos )
187  {
188  GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
189  mMultipartGeos = nullptr;
190  }
191 
192  mLength = -1;
193  mArea = -1;
194 }
195 
197 {
198  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
199 
200  if ( mGeos && mOwnsGeom )
201  {
202  GEOSGeom_destroy_r( geosctxt, mGeos );
203  mGeos = nullptr;
204  }
205  GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
206 
207  if ( mGeosPreparedBoundary )
208  {
209  GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
210  mGeosPreparedBoundary = nullptr;
211  }
212 
213  if ( mMultipartPreparedGeos )
214  {
215  GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
216  mMultipartPreparedGeos = nullptr;
217  }
218  if ( mMultipartGeos )
219  {
220  GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
221  mMultipartGeos = nullptr;
222  }
223 
224  deleteCoords();
225 }
226 
228 {
229  x.clear();
230  y.clear();
231 }
232 
233 std::unique_ptr<PointSet> PointSet::extractShape( int nbPtSh, int imin, int imax, int fps, int fpe, double fptx, double fpty )
234 {
235  int i, j;
236 
237  std::unique_ptr<PointSet> newShape = std::make_unique< PointSet >();
238  newShape->type = GEOS_POLYGON;
239  newShape->nbPoints = nbPtSh;
240  newShape->x.resize( newShape->nbPoints );
241  newShape->y.resize( newShape->nbPoints );
242 
243  // new shape # 1 from imin to imax
244  for ( j = 0, i = imin; i != ( imax + 1 ) % nbPoints; i = ( i + 1 ) % nbPoints, j++ )
245  {
246  newShape->x[j] = x[i];
247  newShape->y[j] = y[i];
248  }
249  // is the cutting point a new one ?
250  if ( fps != fpe )
251  {
252  // yes => so add it
253  newShape->x[j] = fptx;
254  newShape->y[j] = fpty;
255  }
256 
257  return newShape;
258 }
259 
260 std::unique_ptr<PointSet> PointSet::clone() const
261 {
262  return std::unique_ptr< PointSet>( new PointSet( *this ) );
263 }
264 
265 bool PointSet::containsPoint( double x, double y ) const
266 {
267  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
268  try
269  {
270 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
271  geos::unique_ptr point( GEOSGeom_createPointFromXY_r( geosctxt, x, y ) );
272 #else
273  GEOSCoordSequence *seq = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
274  GEOSCoordSeq_setX_r( geosctxt, seq, 0, x );
275  GEOSCoordSeq_setY_r( geosctxt, seq, 0, y );
276  geos::unique_ptr point( GEOSGeom_createPoint_r( geosctxt, seq ) );
277 #endif
278  const bool result = ( GEOSPreparedContainsProperly_r( geosctxt, preparedGeom(), point.get() ) == 1 );
279 
280  return result;
281  }
282  catch ( GEOSException &e )
283  {
284  qWarning( "GEOS exception: %s", e.what() );
285  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
286  return false;
287  }
288 
289 }
290 
291 bool PointSet::containsLabelCandidate( double x, double y, double width, double height, double alpha ) const
292 {
293  return GeomFunction::containsCandidate( preparedGeom(), x, y, width, height, alpha );
294 }
295 
296 QLinkedList<PointSet *> PointSet::splitPolygons( PointSet *inputShape, double labelWidth, double labelHeight )
297 {
298  int j;
299 
300  double bestArea = 0;
301 
302  double b;
303 
304  int holeS = -1; // hole start and end points
305  int holeE = -1;
306 
307  int retainedPt = -1;
308 
309  const double labelArea = labelWidth * labelHeight;
310 
311  QLinkedList<PointSet *> inputShapes;
312  inputShapes.push_back( inputShape );
313  QLinkedList<PointSet *> outputShapes;
314 
315  while ( !inputShapes.isEmpty() )
316  {
317  PointSet *shape = inputShapes.takeFirst();
318 
319  const std::vector< double > &x = shape->x;
320  const std::vector< double > &y = shape->y;
321  const int nbp = shape->nbPoints;
322  std::vector< int > pts( nbp );
323  for ( int i = 0; i < nbp; i++ )
324  {
325  pts[i] = i;
326  }
327 
328  // compute convex hull
329  shape->convexHull = GeomFunction::convexHullId( pts, x, y );
330 
331  bestArea = 0;
332  retainedPt = -1;
333 
334  // lookup for a hole
335  for ( std::size_t ihs = 0; ihs < shape->convexHull.size(); ihs++ )
336  {
337  // ihs->ihn => cHull'seg
338  const std::size_t ihn = ( ihs + 1 ) % shape->convexHull.size();
339 
340  const int ips = shape->convexHull[ihs];
341  const int ipn = ( ips + 1 ) % nbp;
342  if ( ipn != shape->convexHull[ihn] ) // next point on shape is not the next point on cHull => there is a hole here !
343  {
344  double bestcp = 0;
345  int pt = -1;
346  // lookup for the deepest point in the hole
347  for ( int i = ips; i != shape->convexHull[ihn]; i = ( i + 1 ) % nbp )
348  {
349  const double cp = std::fabs( GeomFunction::cross_product( x[shape->convexHull[ihs]], y[shape->convexHull[ihs]],
350  x[shape->convexHull[ihn]], y[shape->convexHull[ihn]],
351  x[i], y[i] ) );
352  if ( cp - bestcp > EPSILON )
353  {
354  bestcp = cp;
355  pt = i;
356  }
357  }
358 
359  if ( pt != -1 )
360  {
361  // compute the ihs->ihn->pt triangle's area
362  const double base = GeomFunction::dist_euc2d( x[shape->convexHull[ihs]], y[shape->convexHull[ihs]],
363  x[shape->convexHull[ihn]], y[shape->convexHull[ihn]] );
364 
365  b = GeomFunction::dist_euc2d( x[shape->convexHull[ihs]], y[shape->convexHull[ihs]],
366  x[pt], y[pt] );
367 
368  const double c = GeomFunction::dist_euc2d( x[shape->convexHull[ihn]], y[shape->convexHull[ihn]],
369  x[pt], y[pt] );
370 
371  const double s = ( base + b + c ) / 2; // s = half perimeter
372  double area = s * ( s - base ) * ( s - b ) * ( s - c );
373  if ( area < 0 )
374  area = -area;
375 
376  // retain the biggest area
377  if ( area - bestArea > EPSILON )
378  {
379  bestArea = area;
380  retainedPt = pt;
381  holeS = ihs;
382  holeE = ihn;
383  }
384  }
385  }
386  }
387 
388  // we have a hole, its area, and the deppest point in hole
389  // we're going to find the second point to cup the shape
390  // holeS = hole starting point
391  // holeE = hole ending point
392  // retainedPt = deppest point in hole
393  // bestArea = area of triangle HoleS->holeE->retainedPoint
394  bestArea = std::sqrt( bestArea );
395  double cx, cy, dx, dy, ex, ey, fx, fy, seg_length, ptx = 0, pty = 0, fptx = 0, fpty = 0;
396  int ps = -1, pe = -1, fps = -1, fpe = -1;
397  if ( retainedPt >= 0 && bestArea > labelArea ) // there is a hole so we'll cut the shape in two new shape (only if hole area is bigger than twice labelArea)
398  {
399  double c = std::numeric_limits<double>::max();
400 
401  // iterate on all shape points except points which are in the hole
402  bool isValid;
403  int k, l;
404  for ( int i = ( shape->convexHull[holeE] + 1 ) % nbp; i != ( shape->convexHull[holeS] - 1 + nbp ) % nbp; i = j )
405  {
406  j = ( i + 1 ) % nbp; // i->j is shape segment not in hole
407 
408  // compute distance between retainedPoint and segment
409  // whether perpendicular distance (if retaindPoint is fronting segment i->j)
410  // or distance between retainedPt and i or j (choose the nearest)
411  seg_length = GeomFunction::dist_euc2d( x[i], y[i], x[j], y[j] );
412  cx = ( x[i] + x[j] ) / 2.0;
413  cy = ( y[i] + y[j] ) / 2.0;
414  dx = cy - y[i];
415  dy = cx - x[i];
416 
417  ex = cx - dx;
418  ey = cy + dy;
419  fx = cx + dx;
420  fy = cy - dy;
421 
422  if ( seg_length < EPSILON || std::fabs( ( b = GeomFunction::cross_product( ex, ey, fx, fy, x[retainedPt], y[retainedPt] ) / ( seg_length ) ) ) > ( seg_length / 2 ) ) // retainedPt is not fronting i->j
423  {
424  if ( ( ex = GeomFunction::dist_euc2d_sq( x[i], y[i], x[retainedPt], y[retainedPt] ) ) < ( ey = GeomFunction::dist_euc2d_sq( x[j], y[j], x[retainedPt], y[retainedPt] ) ) )
425  {
426  b = ex;
427  ps = i;
428  pe = i;
429  }
430  else
431  {
432  b = ey;
433  ps = j;
434  pe = j;
435  }
436  }
437  else // point fronting i->j => compute pependicular distance => create a new point
438  {
439  b = GeomFunction::cross_product( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt] ) / seg_length;
440  b *= b;
441  ps = i;
442  pe = j;
443 
444  if ( !GeomFunction::computeLineIntersection( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt], x[retainedPt] - dx, y[retainedPt] + dy, &ptx, &pty ) )
445  {
446  //error - it should intersect the line
447  }
448  }
449 
450  isValid = true;
451  double pointX, pointY;
452  if ( ps == pe )
453  {
454  pointX = x[pe];
455  pointY = y[pe];
456  }
457  else
458  {
459  pointX = ptx;
460  pointY = pty;
461  }
462 
463  for ( k = shape->convexHull[holeS]; k != shape->convexHull[holeE]; k = ( k + 1 ) % nbp )
464  {
465  l = ( k + 1 ) % nbp;
466  if ( GeomFunction::isSegIntersects( x[retainedPt], y[retainedPt], pointX, pointY, x[k], y[k], x[l], y[l] ) )
467  {
468  isValid = false;
469  break;
470  }
471  }
472 
473 
474  if ( isValid && b < c )
475  {
476  c = b;
477  fps = ps;
478  fpe = pe;
479  fptx = ptx;
480  fpty = pty;
481  }
482  } // for point which are not in hole
483 
484  // we will cut the shapeu in two new shapes, one from [retainedPoint] to [newPoint] and one form [newPoint] to [retainedPoint]
485  const int imin = retainedPt;
486  int imax = ( ( ( fps < retainedPt && fpe < retainedPt ) || ( fps > retainedPt && fpe > retainedPt ) ) ? std::min( fps, fpe ) : std::max( fps, fpe ) );
487 
488  int nbPtSh1, nbPtSh2; // how many points in new shapes ?
489  if ( imax > imin )
490  nbPtSh1 = imax - imin + 1 + ( fpe != fps );
491  else
492  nbPtSh1 = imax + nbp - imin + 1 + ( fpe != fps );
493 
494  if ( ( imax == fps ? fpe : fps ) < imin )
495  nbPtSh2 = imin - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
496  else
497  nbPtSh2 = imin + nbp - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
498 
499  if ( retainedPt == -1 || fps == -1 || fpe == -1 )
500  {
501  if ( shape->parent )
502  delete shape;
503  }
504  // check for useless splitting
505  else if ( imax == imin || nbPtSh1 <= 2 || nbPtSh2 <= 2 || nbPtSh1 == nbp || nbPtSh2 == nbp )
506  {
507  outputShapes.append( shape );
508  }
509  else
510  {
511 
512  PointSet *newShape = shape->extractShape( nbPtSh1, imin, imax, fps, fpe, fptx, fpty ).release();
513 
514  if ( shape->parent )
515  newShape->parent = shape->parent;
516  else
517  newShape->parent = shape;
518 
519  inputShapes.append( newShape );
520 
521  if ( imax == fps )
522  imax = fpe;
523  else
524  imax = fps;
525 
526  newShape = shape->extractShape( nbPtSh2, imax, imin, fps, fpe, fptx, fpty ).release();
527 
528  if ( shape->parent )
529  newShape->parent = shape->parent;
530  else
531  newShape->parent = shape;
532 
533  inputShapes.append( newShape );
534 
535  if ( shape->parent )
536  delete shape;
537  }
538  }
539  else
540  {
541  outputShapes.append( shape );
542  }
543  }
544  return outputShapes;
545 }
546 
547 void PointSet::offsetCurveByDistance( double distance )
548 {
549  if ( !mGeos )
550  createGeosGeom();
551 
552  if ( !mGeos || type != GEOS_LINESTRING )
553  return;
554 
555  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
556  geos::unique_ptr newGeos = nullptr;
557  try
558  {
559  newGeos.reset( GEOSOffsetCurve_r( geosctxt, mGeos, distance, 0, GEOSBUF_JOIN_MITRE, 2 ) );
560  if ( !newGeos )
561  return;
562 
563  // happens sometime, if the offset curve self-intersects
564  if ( GEOSGeomTypeId_r( geosctxt, newGeos.get() ) == GEOS_MULTILINESTRING )
565  {
566  // we keep the longest part
567  const int nParts = GEOSGetNumGeometries_r( geosctxt, newGeos.get() );
568  double maximumLength = -1;
569  const GEOSGeometry *longestPart = nullptr;
570  for ( int i = 0; i < nParts; ++i )
571  {
572  const GEOSGeometry *part = GEOSGetGeometryN_r( geosctxt, newGeos.get(), i );
573  double partLength = -1;
574  if ( GEOSLength_r( geosctxt, part, &partLength ) == 1 )
575  {
576  if ( partLength > maximumLength )
577  {
578  maximumLength = partLength;
579  longestPart = part;
580  }
581  }
582  }
583 
584  if ( !longestPart )
585  {
586  // something is really wrong!
587  return;
588  }
589 
590  geos::unique_ptr longestPartClone( GEOSGeom_clone_r( geosctxt, longestPart ) );
591  newGeos = std::move( longestPartClone );
592  }
593 
594  if ( distance < 0 )
595  {
596  // geos reverses the direction of offset curves with negative distances -- we don't want that!
597  geos::unique_ptr reversed( GEOSReverse_r( geosctxt, newGeos.get() ) );
598  if ( !reversed )
599  return;
600 
601  newGeos = std::move( reversed );
602  }
603 
604  const int newNbPoints = GEOSGeomGetNumPoints_r( geosctxt, newGeos.get() );
605  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, newGeos.get() );
606  std::vector< double > newX;
607  std::vector< double > newY;
608  newX.resize( newNbPoints );
609  newY.resize( newNbPoints );
610  for ( int i = 0; i < newNbPoints; i++ )
611  {
612  GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &newX[i] );
613  GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &newY[i] );
614  }
615  nbPoints = newNbPoints;
616  x = newX;
617  y = newY;
618  }
619  catch ( GEOSException &e )
620  {
621  qWarning( "GEOS exception: %s", e.what() );
622  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
623  return;
624  }
625 
626  invalidateGeos();
627  mGeos = newGeos.release();
628  mOwnsGeom = true;
629 }
630 
631 void PointSet::extendLineByDistance( double startDistance, double endDistance, double smoothDistance )
632 {
633  if ( nbPoints < 2 )
634  return;
635 
636  double x0 = x[0];
637  double y0 = y[0];
638  if ( startDistance > 0 )
639  {
640  // trace forward by smoothDistance
641  double x1 = x[1];
642  double y1 = y[1];
643 
644  double distanceConsumed = 0;
645  double lastX = x0;
646  double lastY = y0;
647  for ( int i = 1; i < nbPoints; ++i )
648  {
649  const double thisX = x[i];
650  const double thisY = y[i];
651  const double thisSegmentLength = std::sqrt( ( thisX - lastX ) * ( thisX - lastX ) + ( thisY - lastY ) * ( thisY - lastY ) );
652  distanceConsumed += thisSegmentLength;
653  if ( distanceConsumed >= smoothDistance )
654  {
655  const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
656  x1 = lastX + c * ( thisX - lastX );
657  y1 = lastY + c * ( thisY - lastY );
658  break;
659  }
660  lastX = thisX;
661  lastY = thisY;
662  }
663 
664  const double distance = std::sqrt( ( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 ) );
665  const double extensionFactor = ( startDistance + distance ) / distance;
666  const QgsPointXY newStart = QgsGeometryUtils::interpolatePointOnLine( x1, y1, x0, y0, extensionFactor );
667  x0 = newStart.x();
668  y0 = newStart.y();
669  // defer actually changing the stored start until we've calculated the new end point
670  }
671 
672  if ( endDistance > 0 )
673  {
674  const double xend0 = x[nbPoints - 1];
675  const double yend0 = y[nbPoints - 1];
676  double xend1 = x[nbPoints - 2];
677  double yend1 = y[nbPoints - 2];
678 
679  // trace backward by smoothDistance
680  double distanceConsumed = 0;
681  double lastX = x0;
682  double lastY = y0;
683  for ( int i = nbPoints - 2; i >= 0; --i )
684  {
685  const double thisX = x[i];
686  const double thisY = y[i];
687  const double thisSegmentLength = std::sqrt( ( thisX - lastX ) * ( thisX - lastX ) + ( thisY - lastY ) * ( thisY - lastY ) );
688  distanceConsumed += thisSegmentLength;
689  if ( distanceConsumed >= smoothDistance )
690  {
691  const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
692  xend1 = lastX + c * ( thisX - lastX );
693  yend1 = lastY + c * ( thisY - lastY );
694  break;
695  }
696  lastX = thisX;
697  lastY = thisY;
698  }
699 
700  const double distance = std::sqrt( ( xend1 - xend0 ) * ( xend1 - xend0 ) + ( yend1 - yend0 ) * ( yend1 - yend0 ) );
701  const double extensionFactor = ( endDistance + distance ) / distance;
702  const QgsPointXY newEnd = QgsGeometryUtils::interpolatePointOnLine( xend1, yend1, xend0, yend0, extensionFactor );
703  x.emplace_back( newEnd.x() );
704  y.emplace_back( newEnd.y() );
705  nbPoints++;
706  }
707 
708  if ( startDistance > 0 )
709  {
710  x.insert( x.begin(), x0 );
711  y.insert( y.begin(), y0 );
712  nbPoints++;
713  }
714 
715  invalidateGeos();
716 }
717 
719 {
720  ok = false;
721  double bbox[4]; // xmin, ymin, xmax, ymax
722 
723  double alpha;
724  int alpha_d;
725 
726  double alpha_seg;
727 
728  double d1, d2;
729 
730  double bb[16]; // {ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy, gx, gy, hx, hy}}
731 
732  double best_area = std::numeric_limits<double>::max();
733  double best_alpha = -1;
734  double best_bb[16];
735  double best_length = 0;
736  double best_width = 0;
737 
738 
739  bbox[0] = std::numeric_limits<double>::max();
740  bbox[1] = std::numeric_limits<double>::max();
741  bbox[2] = std::numeric_limits<double>::lowest();
742  bbox[3] = std::numeric_limits<double>::lowest();
743 
744  for ( std::size_t i = 0; i < convexHull.size(); i++ )
745  {
746  if ( x[convexHull[i]] < bbox[0] )
747  bbox[0] = x[convexHull[i]];
748 
749  if ( x[convexHull[i]] > bbox[2] )
750  bbox[2] = x[convexHull[i]];
751 
752  if ( y[convexHull[i]] < bbox[1] )
753  bbox[1] = y[convexHull[i]];
754 
755  if ( y[convexHull[i]] > bbox[3] )
756  bbox[3] = y[convexHull[i]];
757  }
758 
760 
761  const double dref = bbox[2] - bbox[0];
762  if ( qgsDoubleNear( dref, 0 ) )
763  {
764  ok = false;
765  return finalBb;
766  }
767 
768  for ( alpha_d = 0; alpha_d < 90; alpha_d++ )
769  {
770  alpha = alpha_d * M_PI / 180.0;
771  d1 = std::cos( alpha ) * dref;
772  d2 = std::sin( alpha ) * dref;
773 
774  bb[0] = bbox[0];
775  bb[1] = bbox[3]; // ax, ay
776 
777  bb[4] = bbox[0];
778  bb[5] = bbox[1]; // cx, cy
779 
780  bb[8] = bbox[2];
781  bb[9] = bbox[1]; // ex, ey
782 
783  bb[12] = bbox[2];
784  bb[13] = bbox[3]; // gx, gy
785 
786 
787  bb[2] = bb[0] + d1;
788  bb[3] = bb[1] + d2; // bx, by
789  bb[6] = bb[4] - d2;
790  bb[7] = bb[5] + d1; // dx, dy
791  bb[10] = bb[8] - d1;
792  bb[11] = bb[9] - d2; // fx, fy
793  bb[14] = bb[12] + d2;
794  bb[15] = bb[13] - d1; // hx, hy
795 
796  // adjust all points
797  for ( int i = 0; i < 16; i += 4 )
798  {
799 
800  alpha_seg = ( ( i / 4 > 0 ? ( i / 4 ) - 1 : 3 ) ) * M_PI_2 + alpha;
801 
802  double best_cp = std::numeric_limits<double>::max();
803 
804  for ( std::size_t j = 0; j < convexHull.size(); j++ )
805  {
806  const double cp = GeomFunction::cross_product( bb[i + 2], bb[i + 3], bb[i], bb[i + 1], x[convexHull[j]], y[convexHull[j]] );
807  if ( cp < best_cp )
808  {
809  best_cp = cp;
810  }
811  }
812 
813  const double distNearestPoint = best_cp / dref;
814 
815  d1 = std::cos( alpha_seg ) * distNearestPoint;
816  d2 = std::sin( alpha_seg ) * distNearestPoint;
817 
818  bb[i] += d1; // x
819  bb[i + 1] += d2; // y
820  bb[i + 2] += d1; // x
821  bb[i + 3] += d2; // y
822  }
823 
824  // compute and compare AREA
825  const double width = GeomFunction::cross_product( bb[6], bb[7], bb[4], bb[5], bb[12], bb[13] ) / dref;
826  const double length = GeomFunction::cross_product( bb[2], bb[3], bb[0], bb[1], bb[8], bb[9] ) / dref;
827 
828  double area = width * length;
829 
830  if ( area < 0 )
831  area *= -1;
832 
833 
834  if ( best_area - area > EPSILON )
835  {
836  best_area = area;
837  best_length = length;
838  best_width = width;
839  best_alpha = alpha;
840  memcpy( best_bb, bb, sizeof( double ) * 16 );
841  }
842  }
843 
844  // best bbox is defined
845  for ( int i = 0; i < 16; i = i + 4 )
846  {
847  GeomFunction::computeLineIntersection( best_bb[i], best_bb[i + 1], best_bb[i + 2], best_bb[i + 3],
848  best_bb[( i + 4 ) % 16], best_bb[( i + 5 ) % 16], best_bb[( i + 6 ) % 16], best_bb[( i + 7 ) % 16],
849  &finalBb.x[int ( i / 4 )], &finalBb.y[int ( i / 4 )] );
850  }
851 
852  finalBb.alpha = best_alpha;
853  finalBb.width = best_width;
854  finalBb.length = best_length;
855 
856  ok = true;
857  return finalBb;
858 }
859 
860 double PointSet::minDistanceToPoint( double px, double py, double *rx, double *ry ) const
861 {
862  if ( !mGeos )
863  createGeosGeom();
864 
865  if ( !mGeos )
866  return 0;
867 
868  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
869  try
870  {
871 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
872  geos::unique_ptr geosPt( GEOSGeom_createPointFromXY_r( geosctxt, px, py ) );
873 #else
874  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
875  GEOSCoordSeq_setX_r( geosctxt, coord, 0, px );
876  GEOSCoordSeq_setY_r( geosctxt, coord, 0, py );
877  geos::unique_ptr geosPt( GEOSGeom_createPoint_r( geosctxt, coord ) );
878 #endif
879  const int type = GEOSGeomTypeId_r( geosctxt, mGeos );
880  const GEOSGeometry *extRing = nullptr;
881 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=9
882  const GEOSPreparedGeometry *preparedExtRing = nullptr;
883 #endif
884 
885  if ( type != GEOS_POLYGON )
886  {
887  extRing = mGeos;
888 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=9
889  preparedExtRing = preparedGeom();
890 #endif
891  }
892  else
893  {
894  //for polygons, we want distance to exterior ring (not an interior point)
895  extRing = GEOSGetExteriorRing_r( geosctxt, mGeos );
896 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
897  if ( ! mGeosPreparedBoundary )
898  {
899  mGeosPreparedBoundary = GEOSPrepare_r( geosctxt, extRing );
900  }
901  preparedExtRing = mGeosPreparedBoundary;
902 #endif
903  }
904 
905 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
906  const geos::coord_sequence_unique_ptr nearestCoord( GEOSPreparedNearestPoints_r( geosctxt, preparedExtRing, geosPt.get() ) );
907 #else
908  geos::coord_sequence_unique_ptr nearestCoord( GEOSNearestPoints_r( geosctxt, extRing, geosPt.get() ) );
909 #endif
910  double nx;
911  double ny;
912 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
913  unsigned int nPoints = 0;
914  GEOSCoordSeq_getSize_r( geosctxt, nearestCoord.get(), &nPoints );
915  if ( nPoints == 0 )
916  return 0;
917 
918  ( void )GEOSCoordSeq_getXY_r( geosctxt, nearestCoord.get(), 0, &nx, &ny );
919 #else
920  ( void )GEOSCoordSeq_getX_r( geosctxt, nearestCoord.get(), 0, &nx );
921  ( void )GEOSCoordSeq_getY_r( geosctxt, nearestCoord.get(), 0, &ny );
922 #endif
923 
924  if ( rx )
925  *rx = nx;
926  if ( ry )
927  *ry = ny;
928 
929  return GeomFunction::dist_euc2d_sq( px, py, nx, ny );
930  }
931  catch ( GEOSException &e )
932  {
933  qWarning( "GEOS exception: %s", e.what() );
934  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
935  return 0;
936  }
937 }
938 
939 void PointSet::getCentroid( double &px, double &py, bool forceInside ) const
940 {
941  if ( !mGeos )
942  createGeosGeom();
943 
944  if ( !mGeos )
945  return;
946 
947  try
948  {
949  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
950  geos::unique_ptr centroidGeom( GEOSGetCentroid_r( geosctxt, mGeos ) );
951  if ( centroidGeom )
952  {
953  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, centroidGeom.get() );
954 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
955  unsigned int nPoints = 0;
956  GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
957  if ( nPoints == 0 )
958  return;
959  GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
960 #else
961  GEOSCoordSeq_getX_r( geosctxt, coordSeq, 0, &px );
962  GEOSCoordSeq_getY_r( geosctxt, coordSeq, 0, &py );
963 #endif
964  }
965 
966  // check if centroid inside in polygon
967  if ( forceInside && !containsPoint( px, py ) )
968  {
969  geos::unique_ptr pointGeom( GEOSPointOnSurface_r( geosctxt, mGeos ) );
970 
971  if ( pointGeom )
972  {
973  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
974 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
975  unsigned int nPoints = 0;
976  GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
977  if ( nPoints == 0 )
978  return;
979 
980  GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
981 #else
982  GEOSCoordSeq_getX_r( geosctxt, coordSeq, 0, &px );
983  GEOSCoordSeq_getY_r( geosctxt, coordSeq, 0, &py );
984 #endif
985  }
986  }
987  }
988  catch ( GEOSException &e )
989  {
990  qWarning( "GEOS exception: %s", e.what() );
991  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
992  return;
993  }
994 }
995 
996 bool PointSet::boundingBoxIntersects( const PointSet *other ) const
997 {
998  const double x1 = ( xmin > other->xmin ? xmin : other->xmin );
999  const double x2 = ( xmax < other->xmax ? xmax : other->xmax );
1000  if ( x1 > x2 )
1001  return false;
1002  const double y1 = ( ymin > other->ymin ? ymin : other->ymin );
1003  const double y2 = ( ymax < other->ymax ? ymax : other->ymax );
1004  return y1 <= y2;
1005 }
1006 
1007 void PointSet::getPointByDistance( double *d, double *ad, double dl, double *px, double *py ) const
1008 {
1009  int i;
1010  double dx, dy, di;
1011  double distr;
1012 
1013  i = 0;
1014  if ( dl >= 0 )
1015  {
1016  while ( i < nbPoints && ad[i] <= dl ) i++;
1017  i--;
1018  }
1019 
1020  if ( i < nbPoints - 1 )
1021  {
1022  if ( dl < 0 )
1023  {
1024  dx = x[nbPoints - 1] - x[0];
1025  dy = y[nbPoints - 1] - y[0];
1026  di = std::sqrt( dx * dx + dy * dy );
1027  }
1028  else
1029  {
1030  dx = x[i + 1] - x[i];
1031  dy = y[i + 1] - y[i];
1032  di = d[i];
1033  }
1034 
1035  distr = dl - ad[i];
1036  *px = x[i] + dx * distr / di;
1037  *py = y[i] + dy * distr / di;
1038  }
1039  else // just select last point...
1040  {
1041  *px = x[i];
1042  *py = y[i];
1043  }
1044 }
1045 
1047 {
1048  const GEOSGeometry *thisGeos = geos();
1049  if ( !thisGeos )
1050  return nullptr;
1051 
1052  try
1053  {
1054  geos::unique_ptr res( GEOSInterpolate_r( QgsGeos::getGEOSHandler(), thisGeos, distance ) );
1055  return res;
1056  }
1057  catch ( GEOSException &e )
1058  {
1059  qWarning( "GEOS exception: %s", e.what() );
1060  return nullptr;
1061  }
1062 }
1063 
1064 double PointSet::lineLocatePoint( const GEOSGeometry *point ) const
1065 {
1066  const GEOSGeometry *thisGeos = geos();
1067  if ( !thisGeos )
1068  return -1;
1069 
1070  double distance = -1;
1071  try
1072  {
1073  distance = GEOSProject_r( QgsGeos::getGEOSHandler(), thisGeos, point );
1074  }
1075  catch ( GEOSException &e )
1076  {
1077  qWarning( "GEOS exception: %s", e.what() );
1078  return -1;
1079  }
1080 
1081  return distance;
1082 }
1083 
1084 const GEOSGeometry *PointSet::geos() const
1085 {
1086  if ( !mGeos )
1087  createGeosGeom();
1088 
1089  return mGeos;
1090 }
1091 
1092 double PointSet::length() const
1093 {
1094  if ( mLength >= 0 )
1095  return mLength;
1096 
1097  if ( !mGeos )
1098  createGeosGeom();
1099 
1100  if ( !mGeos )
1101  return -1;
1102 
1103  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
1104 
1105  try
1106  {
1107  ( void )GEOSLength_r( geosctxt, mGeos, &mLength );
1108  return mLength;
1109  }
1110  catch ( GEOSException &e )
1111  {
1112  qWarning( "GEOS exception: %s", e.what() );
1113  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
1114  return -1;
1115  }
1116 }
1117 
1118 double PointSet::area() const
1119 {
1120  if ( mArea >= 0 )
1121  return mArea;
1122 
1123  if ( !mGeos )
1124  createGeosGeom();
1125 
1126  if ( !mGeos )
1127  return -1;
1128 
1129  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
1130 
1131  try
1132  {
1133  ( void )GEOSArea_r( geosctxt, mGeos, &mArea );
1134  mArea = std::fabs( mArea );
1135  return mArea;
1136  }
1137  catch ( GEOSException &e )
1138  {
1139  qWarning( "GEOS exception: %s", e.what() );
1140  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
1141  return -1;
1142  }
1143 }
1144 
1146 {
1147  return qgsDoubleNear( x[0], x[nbPoints - 1] ) && qgsDoubleNear( y[0], y[nbPoints - 1] );
1148 }
1149 
1150 QString PointSet::toWkt() const
1151 {
1152  if ( !mGeos )
1153  createGeosGeom();
1154 
1155  GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
1156 
1157  try
1158  {
1159  GEOSWKTWriter *writer = GEOSWKTWriter_create_r( geosctxt );
1160 
1161  char *wkt = GEOSWKTWriter_write_r( geosctxt, writer, mGeos );
1162  const QString res( wkt );
1163 
1164  GEOSFree_r( geosctxt, wkt );
1165 
1166  GEOSWKTWriter_destroy_r( geosctxt, writer );
1167  writer = nullptr;
1168 
1169  return res;
1170  }
1171  catch ( GEOSException &e )
1172  {
1173  qWarning( "GEOS exception: %s", e.what() );
1174  QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
1175  return QString();
1176  }
1177 }
1178 
1179 std::tuple< std::vector< double >, double > PointSet::edgeDistances() const
1180 {
1181  std::vector< double > distances( nbPoints );
1182  double totalDistance = 0;
1183  double oldX = -1.0, oldY = -1.0;
1184  for ( int i = 0; i < nbPoints; i++ )
1185  {
1186  if ( i == 0 )
1187  distances[i] = 0;
1188  else
1189  distances[i] = std::sqrt( std::pow( oldX - x[i], 2 ) + std::pow( oldY - y[i], 2 ) );
1190 
1191  oldX = x[i];
1192  oldY = y[i];
1193  totalDistance += distances[i];
1194  }
1195  return std::make_tuple( std::move( distances ), totalDistance );
1196 }
pal::PointSet::mArea
double mArea
Definition: pointset.h:244
pal::PointSet::length
double length() const
Returns length of line geometry.
Definition: pointset.cpp:1092
pal::PointSet::xmax
double xmax
Definition: pointset.h:259
pal::GeomFunction::dist_euc2d
static double dist_euc2d(double x1, double y1, double x2, double y2)
Definition: geomfunction.h:67
QgsPointXY::y
double y
Definition: qgspointxy.h:63
pal::GeomFunction::dist_euc2d_sq
static double dist_euc2d_sq(double x1, double y1, double x2, double y2)
Definition: geomfunction.h:72
pal::OrientedConvexHullBoundingBox::length
double length
Definition: pointset.h:67
pal::PointSet::edgeDistances
std::tuple< std::vector< double >, double > edgeDistances() const
Returns a vector of edge distances as well as its total length.
Definition: pointset.cpp:1179
EPSILON
#define EPSILON
Definition: util.h:78
pal::PointSet::interpolatePoint
geos::unique_ptr interpolatePoint(double distance) const
Returns a GEOS geometry representing the point interpolated on the shape by distance.
Definition: pointset.cpp:1046
pal::OrientedConvexHullBoundingBox::y
double y[4]
Definition: pointset.h:62
pal::PointSet::~PointSet
virtual ~PointSet()
Definition: pointset.cpp:196
pal::PointSet::mOwnsGeom
bool mOwnsGeom
Definition: pointset.h:235
pal::PointSet::splitPolygons
static QLinkedList< PointSet * > splitPolygons(PointSet *inputShape, double labelWidth, double labelHeight)
Split a polygon using some random logic into some other polygons.
Definition: pointset.cpp:296
pal::PointSet::offsetCurveByDistance
void offsetCurveByDistance(double distance)
Offsets linestrings by the specified distance.
Definition: pointset.cpp:547
pal::PointSet::deleteCoords
void deleteCoords()
Definition: pointset.cpp:227
pal
Definition: qgsdiagramrenderer.h:50
pal::GeomFunction::computeLineIntersection
static bool computeLineIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double *x, double *y)
Compute the point where two lines intersect.
Definition: geomfunction.cpp:142
pal::PointSet::containsPoint
bool containsPoint(double x, double y) const
Tests whether point set contains a specified point.
Definition: pointset.cpp:265
pal::PointSet::holeOf
PointSet * holeOf
Definition: pointset.h:241
pal::GeomFunction::containsCandidate
static bool containsCandidate(const GEOSPreparedGeometry *geom, double x, double y, double width, double height, double alpha)
Returns true if a GEOS prepared geometry totally contains a label candidate.
Definition: geomfunction.cpp:303
pal::PointSet::isClosed
bool isClosed() const
Returns true if pointset is closed.
Definition: pointset.cpp:1145
geos::unique_ptr
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Definition: qgsgeos.h:79
pal::PointSet::geos
const GEOSGeometry * geos() const
Returns the point set's GEOS geometry.
Definition: pointset.cpp:1084
pal::PointSet::ymin
double ymin
Definition: pointset.h:260
pal::PointSet::minDistanceToPoint
double minDistanceToPoint(double px, double py, double *rx=nullptr, double *ry=nullptr) const
Returns the squared minimum distance between the point set geometry and the point (px,...
Definition: pointset.cpp:860
pal::PointSet::extendLineByDistance
void extendLineByDistance(double startDistance, double endDistance, double smoothDistance)
Extends linestrings by the specified amount at the start and end of the line, by extending the existi...
Definition: pointset.cpp:631
pal::PointSet::lineLocatePoint
double lineLocatePoint(const GEOSGeometry *point) const
Returns the distance along the geometry closest to the specified GEOS point.
Definition: pointset.cpp:1064
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
pal::PointSet::boundingBoxIntersects
bool boundingBoxIntersects(const PointSet *other) const
Returns true if the bounding box of this pointset intersects the bounding box of another pointset.
Definition: pointset.cpp:996
pal::PointSet::x
std::vector< double > x
Definition: pointset.h:230
pal::PointSet::type
int type
Definition: pointset.h:239
pal::PointSet::toWkt
QString toWkt() const
Returns a WKT representation of the point set.
Definition: pointset.cpp:1150
geomfunction.h
pointset.h
pal::OrientedConvexHullBoundingBox::width
double width
Definition: pointset.h:66
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
pal::GeomFunction::convexHullId
static std::vector< int > convexHullId(std::vector< int > &id, const std::vector< double > &x, const std::vector< double > &y)
Compute the convex hull in O(n·log(n))
Definition: geomfunction.cpp:172
pal::PointSet::computeConvexHullOrientedBoundingBox
OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox(bool &ok)
Computes an oriented bounding box for the shape's convex hull.
Definition: pointset.cpp:718
pal::PointSet::clone
std::unique_ptr< PointSet > clone() const
Returns a copy of the point set.
Definition: pointset.cpp:260
pal::PointSet::extractShape
std::unique_ptr< PointSet > extractShape(int nbPtSh, int imin, int imax, int fps, int fpe, double fptx, double fpty)
Does...
Definition: pointset.cpp:233
pal::OrientedConvexHullBoundingBox
Represents the minimum area, oriented bounding box surrounding a convex hull.
Definition: pointset.h:59
QgsGeos::getGEOSHandler
static GEOSContextHandle_t getGEOSHandler()
Definition: qgsgeos.cpp:3369
qgsgeometryutils.h
pal::PointSet::createGeosGeom
void createGeosGeom() const
Definition: pointset.cpp:99
pal::PointSet::convexHull
std::vector< int > convexHull
Definition: pointset.h:237
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
pal::PointSet::containsLabelCandidate
bool containsLabelCandidate(double x, double y, double width, double height, double alpha=0) const
Tests whether a possible label candidate will fit completely within the shape.
Definition: pointset.cpp:291
pal::PointSet::mGeos
GEOSGeometry * mGeos
Definition: pointset.h:234
pal::PointSet::y
std::vector< double > y
Definition: pointset.h:231
pal::PointSet
The underlying raw pal geometry class.
Definition: pointset.h:76
pal::PointSet::parent
PointSet * parent
Definition: pointset.h:242
pal::GeomFunction::isSegIntersects
static bool isSegIntersects(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
Returns true if the two segments intersect.
Definition: geomfunction.cpp:135
pal::PointSet::xmin
double xmin
Definition: pointset.h:258
pal::PointSet::preparedGeom
const GEOSPreparedGeometry * preparedGeom() const
Definition: pointset.cpp:149
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
pal::PointSet::PointSet
PointSet()
Definition: pointset.cpp:40
pal::PointSet::getPointByDistance
void getPointByDistance(double *d, double *ad, double dl, double *px, double *py) const
Gets a point a set distance along a line geometry.
Definition: pointset.cpp:1007
QgsPointXY::x
double x
Definition: qgspointxy.h:62
pal::PointSet::getCentroid
void getCentroid(double &px, double &py, bool forceInside=false) const
Definition: pointset.cpp:939
pal::OrientedConvexHullBoundingBox::alpha
double alpha
Definition: pointset.h:64
geos::coord_sequence_unique_ptr
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
Definition: qgsgeos.h:94
pal::GeomFunction::cross_product
static double cross_product(double x1, double y1, double x2, double y2, double x3, double y3)
Definition: geomfunction.h:62
pal::PointSet::invalidateGeos
void invalidateGeos() const
Definition: pointset.cpp:161
pal::OrientedConvexHullBoundingBox::x
double x[4]
Definition: pointset.h:61
pal::PointSet::mLength
double mLength
Definition: pointset.h:245
util.h
pal::PointSet::nbPoints
int nbPoints
Definition: pointset.h:229
QgsGeometryUtils::interpolatePointOnLine
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
Definition: qgsgeometryutils.cpp:1535
pal::PointSet::area
double area() const
Returns area of polygon geometry.
Definition: pointset.cpp:1118
qgsgeos.h
qgsmessagelog.h
pal::PointSet::ymax
double ymax
Definition: pointset.h:261