QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 #ifndef _POINT_SET_H_
31 #define _POINT_SET_H_
32 
33 #if defined(_VERBOSE_) || (_DEBUG_) || (_DEBUG_FULL_)
34 #include <iostream>
35 #endif
36 
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40 
41 #include <qglobal.h>
42 
43 #include "pointset.h"
44 #include "util.h"
45 
46 #include <pal/pal.h>
47 
48 
49 #include "geomfunction.h"
50 
51 namespace pal
52 {
53 
54 
56  : holeOf( NULL )
57  , parent( NULL )
58  , xmin( DBL_MAX )
59  , xmax( -DBL_MAX )
60  , ymin( DBL_MAX )
61  , ymax( -DBL_MAX )
62  {
63  nbPoints = cHullSize = 0;
64  x = NULL;
65  y = NULL;
66  cHull = NULL;
67  type = -1;
68  }
69 
70  PointSet::PointSet( int nbPoints, double *x, double *y )
71  : cHullSize( 0 )
72  , holeOf( NULL )
73  , parent( NULL )
74  , xmin( DBL_MAX )
75  , xmax( -DBL_MAX )
76  , ymin( DBL_MAX )
77  , ymax( -DBL_MAX )
78  {
79  this->nbPoints = nbPoints;
80  this->x = new double[nbPoints];
81  this->y = new double[nbPoints];
82  int i;
83 
84  for ( i = 0; i < nbPoints; i++ )
85  {
86  this->x[i] = x[i];
87  this->y[i] = y[i];
88  }
89  type = GEOS_POLYGON;
90  cHull = NULL;
91  }
92 
93  PointSet::PointSet( double aX, double aY )
94  : xmin( aX ), xmax( aY )
95  , ymin( aX ), ymax( aY )
96  {
97  nbPoints = cHullSize = 1;
98  x = new double[1];
99  y = new double[1];
100  x[0] = aX;
101  y[0] = aY;
102 
103  cHull = NULL;
104  parent = NULL;
105  holeOf = NULL;
106 
107  type = GEOS_POINT;
108  }
109 
111  : parent( 0 )
112  , xmin( DBL_MAX )
113  , xmax( -DBL_MAX )
114  , ymin( DBL_MAX )
115  , ymax( -DBL_MAX )
116  {
117  int i;
118 
119  nbPoints = ps.nbPoints;
120  x = new double[nbPoints];
121  y = new double[nbPoints];
122 
123  for ( i = 0; i < nbPoints; i++ )
124  {
125  x[i] = ps.x[i];
126  y[i] = ps.y[i];
127  }
128 
129  if ( ps.cHull )
130  {
131  cHullSize = ps.cHullSize;
132  cHull = new int[cHullSize];
133  for ( i = 0; i < cHullSize; i++ )
134  {
135  cHull[i] = ps.cHull[i];
136  }
137  }
138  else
139  {
140  cHull = NULL;
141  cHullSize = 0;
142  }
143 
144  type = ps.type;
145 
146  holeOf = ps.holeOf;
147  }
148 
150  {
151  deleteCoords();
152 
153  if ( cHull )
154  delete[] cHull;
155  }
156 
158  {
159  if ( x )
160  delete[] x;
161  if ( y )
162  delete[] y;
163  x = NULL;
164  y = NULL;
165  }
166 
167 
168 
169 
170  PointSet* PointSet::extractShape( int nbPtSh, int imin, int imax, int fps, int fpe, double fptx, double fpty )
171  {
172 
173  int i, j;
174 
175  PointSet *newShape = new PointSet();
176 
177  newShape->type = GEOS_POLYGON;
178 
179  newShape->nbPoints = nbPtSh;
180 
181  newShape->x = new double[newShape->nbPoints];
182  newShape->y = new double[newShape->nbPoints];
183 #ifdef _DEBUG_FULL_
184  std::cout << "New shape: ";
185 #endif
186  // new shape # 1 from imin to imax
187  for ( j = 0, i = imin; i != ( imax + 1 ) % nbPoints; i = ( i + 1 ) % nbPoints, j++ )
188  {
189  newShape->x[j] = x[i];
190  newShape->y[j] = y[i];
191 #ifdef _DEBUG_FULL_
192  std::cout << x[i] << ";" << y[i] << std::endl;
193 #endif
194  }
195  // is the cutting point a new one ?
196  if ( fps != fpe )
197  {
198  // yes => so add it
199  newShape->x[j] = fptx;
200  newShape->y[j] = fpty;
201 #ifdef _DEBUG_FULL_
202  std::cout << fptx << ";" << fpty << std::endl;
203 #endif
204  }
205 
206 #ifdef _DEBUG_FULL_
207  std::cout << "J = " << j << "/" << newShape->nbPoints << std::endl;
208  std::cout << std::endl;
209  std::cout << "This: " << this << std::endl;
210 #endif
211 
212  return newShape;
213  }
214 
215 
216  void PointSet::splitPolygons( LinkedList<PointSet*> *shapes_toProcess,
217  LinkedList<PointSet*> *shapes_final,
218  double xrm, double yrm, char *uid )
219  {
220 #ifdef _DEBUG_
221  std::cout << "splitPolygons: " << uid << std::endl;
222 #else
223  Q_UNUSED( uid );
224 #endif
225  int i, j;
226 
227  int nbp;
228  double *x;
229  double *y;
230 
231  int *pts;
232 
233  int *cHull;
234  int cHullSize;
235 
236  double cp;
237  double bestcp = 0;
238 
239  double bestArea = 0;
240  double area;
241 
242  double base;
243  double b, c;
244  double s;
245 
246  int ihs;
247  int ihn;
248 
249  int ips;
250  int ipn;
251 
252  int holeS = -1; // hole start and end points
253  int holeE = -1;
254 
255  int retainedPt = -1;
256  int pt = 0;
257 
258  double labelArea = xrm * yrm;
259 
260  PointSet *shape;
261 
262  while ( shapes_toProcess->size() > 0 )
263  {
264 #ifdef _DEBUG_FULL_
265  std::cout << "Shape popping()" << std::endl;
266 #endif
267  shape = shapes_toProcess->pop_front();
268 
269  x = shape->x;
270  y = shape->y;
271  nbp = shape->nbPoints;
272  pts = new int[nbp];
273 
274 #ifdef _DEBUG_FULL_
275  std::cout << "nbp: " << nbp << std::endl;
276  std::cout << " PtSet: ";
277 #endif
278 
279  for ( i = 0; i < nbp; i++ )
280  {
281  pts[i] = i;
282 #ifdef _DEBUG_FULL_
283  std::cout << x[i] << ";" << y[i] << std::endl;
284 #endif
285  }
286 
287 #ifdef _DEBUG_FULL_
288  std::cout << std::endl;
289 #endif
290 
291  // conpute convex hull
292  shape->cHullSize = convexHullId( pts, x, y, nbp, shape->cHull );
293 
294  cHull = shape->cHull;
295  cHullSize = shape->cHullSize;
296 
297 
298 #ifdef _DEBUG_FULL_
299  std::cout << " CHull: ";
300  for ( i = 0; i < cHullSize; i++ )
301  {
302  std::cout << cHull[i] << " ";
303  }
304  std::cout << std::endl;
305 #endif
306 
307  bestArea = 0;
308  retainedPt = -1;
309 
310  // lookup for a hole
311  for ( ihs = 0; ihs < cHullSize; ihs++ )
312  {
313  // ihs->ihn => cHull'seg
314  ihn = ( ihs + 1 ) % cHullSize;
315 
316  ips = cHull[ihs];
317  ipn = ( ips + 1 ) % nbp;
318  if ( ipn != cHull[ihn] ) // next point on shape is not the next point on cHull => there is a hole here !
319  {
320  bestcp = 0;
321  pt = -1;
322  // lookup for the deepest point in the hole
323  for ( i = ips; i != cHull[ihn]; i = ( i + 1 ) % nbp )
324  {
325  cp = vabs( cross_product( x[cHull[ihs]], y[cHull[ihs]],
326  x[cHull[ihn]], y[cHull[ihn]],
327  x[i], y[i] ) );
328  if ( cp - bestcp > EPSILON )
329  {
330  bestcp = cp;
331  pt = i;
332  }
333  }
334 
335 #ifdef _DEBUG_FULL_
336  std::cout << "Deeper POint: " << pt << " between " << ips << " and " << cHull[ihn] << std::endl;
337 #endif
338  if ( pt != -1 )
339  {
340  // compute the ihs->ihn->pt triangle's area
341  base = dist_euc2d( x[cHull[ihs]], y[cHull[ihs]],
342  x[cHull[ihn]], y[cHull[ihn]] );
343 
344  b = dist_euc2d( x[cHull[ihs]], y[cHull[ihs]],
345  x[pt], y[pt] );
346 
347  c = dist_euc2d( x[cHull[ihn]], y[cHull[ihn]],
348  x[pt], y[pt] );
349 
350  s = ( base + b + c ) / 2; // s = half perimeter
351  area = s * ( s - base ) * ( s - b ) * ( s - c );
352  if ( area < 0 )
353  area = -area;
354 
355  // retain the biggest area
356  if ( area - bestArea > EPSILON )
357  {
358  bestArea = area;
359  retainedPt = pt;
360  holeS = ihs;
361  holeE = ihn;
362  }
363  }
364  }
365  }
366 
367  // we have a hole, its area, and the deppest point in hole
368  // we're going to find the second point to cup the shape
369  // holeS = hole starting point
370  // holeE = hole ending point
371  // retainedPt = deppest point in hole
372  // bestArea = area of triangle HoleS->holeE->retainedPoint
373  bestArea = sqrt( bestArea );
374  double cx, cy, dx, dy, ex, ey, fx, fy, seg_length, ptx = 0, pty = 0, fptx = 0, fpty = 0;
375  int ps = -1, pe = -1, fps = -1, fpe = -1;
376  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)
377  {
378 #ifdef _DEBUG_FULL_
379  std::cout << "Trou: " << retainedPt << std::endl;
380  std::cout << "Hole: " << cHull[holeS] << " -> " << cHull[holeE] << std::endl;
381  std::cout << "iterate from " << ( cHull[holeE] + 1 ) % nbp << " to " << ( cHull[holeS] - 1 + nbp ) % nbp << std::endl;
382 #endif
383  c = DBL_MAX;
384 
385 
386  // iterate on all shape points except points which are in the hole
387  bool isValid;
388  int k, l;
389  for ( i = ( cHull[holeE] + 1 ) % nbp; i != ( cHull[holeS] - 1 + nbp ) % nbp; i = j )
390  {
391  j = ( i + 1 ) % nbp; // i->j is shape segment not in hole
392 
393  // compute distance between retainedPoint and segment
394  // whether perpendicular distance (if retaindPoint is fronting segment i->j)
395  // or distance between retainedPt and i or j (choose the nearest)
396  seg_length = dist_euc2d( x[i], y[i], x[j], y[j] );
397  cx = ( x[i] + x[j] ) / 2.0;
398  cy = ( y[i] + y[j] ) / 2.0;
399  dx = cy - y[i];
400  dy = cx - x[i];
401 
402  ex = cx - dx;
403  ey = cy + dy;
404  fx = cx + dx;
405  fy = cy - dy;
406 #ifdef _DEBUG_FULL_
407  std::cout << "D: " << dx << " " << dy << std::endl;
408  std::cout << "seg_length: " << seg_length << std::endl;
409 #endif
410  if ( seg_length < EPSILON || vabs(( b = cross_product( ex, ey, fx, fy, x[retainedPt], y[retainedPt] ) / ( seg_length ) ) ) > ( seg_length / 2 ) ) // retainedPt is not fronting i->j
411  {
412  if (( ex = dist_euc2d_sq( x[i], y[i], x[retainedPt], y[retainedPt] ) ) < ( ey = dist_euc2d_sq( x[j], y[j], x[retainedPt], y[retainedPt] ) ) )
413  {
414  b = ex;
415  ps = i;
416  pe = i;
417  }
418  else
419  {
420  b = ey;
421  ps = j;
422  pe = j;
423  }
424  }
425  else // point fronting i->j => compute pependicular distance => create a new point
426  {
427  b = cross_product( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt] ) / seg_length;
428  b *= b;
429  ps = i;
430  pe = j;
431 
432  if ( !computeLineIntersection( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt], x[retainedPt] - dx, y[retainedPt] + dy, &ptx, &pty ) )
433  {
434  std::cout << "Oups ... il devrait par tomber la..." << std::endl;
435  }
436 #ifdef _DEBUG_FULL_
437  std::cout << "intersection : " << x[i] << " " << y[i] << " " << x[j] << " " << y[j] << " " << x[retainedPt] << " " << y[retainedPt] << " " << x[retainedPt] - dx << " " << y[retainedPt] + dy << std::endl;
438  std::cout << " => " << ptx << ";" << pty << std::endl;
439  std::cout << " cxy> " << cx << ";" << cy << std::endl;
440  std::cout << " dxy> " << dx << ";" << dy << std::endl;
441 #endif
442  }
443 
444  isValid = true;
445  double pointX, pointY;
446  if ( ps == pe )
447  {
448  pointX = x[pe];
449  pointY = y[pe];
450  }
451  else
452  {
453  pointX = ptx;
454  pointY = pty;
455  }
456 
457  for ( k = cHull[holeS]; k != cHull[holeE]; k = ( k + 1 ) % nbp )
458  {
459  l = ( k + 1 ) % nbp;
460  //std::cout << "test " << k << " " << l << std::endl;
461  if ( isSegIntersects( x[retainedPt], y[retainedPt], pointX, pointY, x[k], y[k], x[l], y[l] ) )
462  {
463  isValid = false;
464  //std::cout << "Invalid point" << pe << ps << std::endl;
465  break;
466  }
467  }
468 
469 
470  if ( isValid && b < c )
471  {
472  //std::cout << "new point: " << ps << " " << pe << std::endl;
473  c = b;
474  fps = ps;
475  fpe = pe;
476  fptx = ptx;
477  fpty = pty;
478  }
479  } // for point which are not in hole
480 
481 #ifdef _DEBUG_FULL_
482  std::cout << " cut from " << retainedPt << " to ";
483  if ( fps == fpe )
484  std::cout << "point " << fps << std::endl;
485  else
486  {
487  std::cout << "new point (" << fptx << ";" << fpty << " between " << fps << " and " << fpe << std::endl;
488  }
489 #endif
490 
491  // we will cut the shapeu in two new shapes, one from [retainedPoint] to [newPoint] and one form [newPoint] to [retainedPoint]
492  int imin = retainedPt;
493  int imax = ((( fps < retainedPt && fpe < retainedPt ) || ( fps > retainedPt && fpe > retainedPt ) ) ? min( fps, fpe ) : max( fps, fpe ) );
494 
495  int nbPtSh1, nbPtSh2; // how many points in new shapes ?
496  if ( imax > imin )
497  nbPtSh1 = imax - imin + 1 + ( fpe != fps );
498  else
499  nbPtSh1 = imax + nbp - imin + 1 + ( fpe != fps );
500 
501  if (( imax == fps ? fpe : fps ) < imin )
502  nbPtSh2 = imin - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
503  else
504  nbPtSh2 = imin + nbp - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
505 
506 
507 #ifdef _DEBUG_FULL_
508  std::cout << "imin: " << imin << " imax:" << imax << std::endl;
509 #endif
510  if ( retainedPt == -1 || fps == -1 || fpe == -1 )
511  {
512 #ifdef _DEBUG_
513  std::cout << std::endl << "Failed to split feature !!! (uid=" << uid << ")" << std::endl;
514 #endif
515  if ( shape->parent )
516  delete shape;
517  }
518  // check for useless spliting
519  else if ( imax == imin || nbPtSh1 <= 2 || nbPtSh2 <= 2 || nbPtSh1 == nbp || nbPtSh2 == nbp )
520  {
521  shapes_final->push_back( shape );
522  }
523  else
524  {
525 
526  PointSet *newShape = shape->extractShape( nbPtSh1, imin, imax, fps, fpe, fptx, fpty );
527 
528  if ( shape->parent )
529  newShape->parent = shape->parent;
530  else
531  newShape->parent = shape;
532 
533 #ifdef _DEBUG_FULL_
534  int i = 0;
535  std::cout << "push back:" << std::endl;
536  for ( i = 0; i < newShape->nbPoints; i++ )
537  {
538  std::cout << newShape->x[i] << ";" << newShape->y[i] << std::endl;
539  }
540 #endif
541 
542  shapes_toProcess->push_back( newShape );
543 
544  if ( imax == fps )
545  imax = fpe;
546  else
547  imax = fps;
548 
549  newShape = shape->extractShape( nbPtSh2, imax, imin, fps, fpe, fptx, fpty );
550 
551  if ( shape->parent )
552  newShape->parent = shape->parent;
553  else
554  newShape->parent = shape;
555 
556 #ifdef _DEBUG_FULL_
557  std::cout << "push back:" << std::endl;
558  for ( i = 0; i < newShape->nbPoints; i++ )
559  {
560  std::cout << newShape->x[i] << ";" << newShape->y[i] << std::endl;
561  }
562 #endif
563  shapes_toProcess->push_back( newShape );
564 
565  if ( shape->parent )
566  delete shape;
567  }
568  }
569  else
570  {
571 #ifdef _DEBUG_FULL_
572  std::cout << "Put shape into shapes_final" << std::endl;
573 #endif
574  shapes_final->push_back( shape );
575  }
576  delete[] pts;
577  }
578  }
579 
580 
581  PointSet* PointSet::createProblemSpecificPointSet( double bbmin[2], double bbmax[2], bool *inside )
582  {
583 #ifdef _DEBUG_FULL_
584  std::cout << "CreateProblemSpecific:" << std::endl;
585 #endif
586  PointSet *shape = new PointSet();
587  shape->x = new double[nbPoints];
588  shape->y = new double[nbPoints];
589  shape->nbPoints = nbPoints;
590  shape->type = type;
591 
592  shape->xmin = xmin;
593  shape->xmax = xmax;
594  shape->ymin = ymin;
595  shape->ymax = ymax;
596 
597  *inside = true;
598 
599  for ( int i = 0; i < nbPoints; i++ )
600  {
601  shape->x[i] = this->x[i];
602  shape->y[i] = this->y[i];
603 
604  // check whether it's not outside
605  if ( x[i] < bbmin[0] || x[i] > bbmax[0] || y[i] < bbmin[1] || y[i] > bbmax[1] )
606  *inside = false;
607  }
608 
609  shape->holeOf = NULL;
610  shape->parent = NULL;
611 
612  return shape;
613  }
614 
615 
616 
617 
619  {
620  int i;
621  int j;
622 
623  double bbox[4]; // xmin, ymin, xmax, ymax
624 
625  double alpha;
626  int alpha_d;
627 
628  double alpha_seg;
629 
630  double dref;
631  double d1, d2;
632 
633  double bb[16]; // {ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy, gx, gy, hx, hy}}
634 
635  double cp;
636  double best_cp;
637  double distNearestPoint;
638 
639  double area;
640  double width;
641  double length;
642 
643  double best_area = DBL_MAX;
644  double best_alpha = -1;
645  double best_bb[16];
646  double best_length = 0;
647  double best_width = 0;
648 
649 
650  bbox[0] = DBL_MAX;
651  bbox[1] = DBL_MAX;
652  bbox[2] = - DBL_MAX;
653  bbox[3] = - DBL_MAX;
654 
655 #ifdef _DEBUG_
656  std::cout << "Compute_chull_bbox" << std::endl;
657 #endif
658 
659  for ( i = 0; i < cHullSize; i++ )
660  {
661 #ifdef _DEBUG_FULL_
662  std::cout << x[cHull[i]] << ";" << y[cHull[i]] << std::endl;
663 #endif
664  if ( x[cHull[i]] < bbox[0] )
665  bbox[0] = x[cHull[i]];
666 
667  if ( x[cHull[i]] > bbox[2] )
668  bbox[2] = x[cHull[i]];
669 
670  if ( y[cHull[i]] < bbox[1] )
671  bbox[1] = y[cHull[i]];
672 
673  if ( y[cHull[i]] > bbox[3] )
674  bbox[3] = y[cHull[i]];
675  }
676 
677 
678  dref = bbox[2] - bbox[0];
679 
680  for ( alpha_d = 0; alpha_d < 90; alpha_d++ )
681  {
682  alpha = alpha_d * M_PI / 180.0;
683  d1 = cos( alpha ) * dref;
684  d2 = sin( alpha ) * dref;
685 
686  bb[0] = bbox[0];
687  bb[1] = bbox[3]; // ax, ay
688 
689  bb[4] = bbox[0];
690  bb[5] = bbox[1]; // cx, cy
691 
692  bb[8] = bbox[2];
693  bb[9] = bbox[1]; // ex, ey
694 
695  bb[12] = bbox[2];
696  bb[13] = bbox[3]; // gx, gy
697 
698 
699  bb[2] = bb[0] + d1;
700  bb[3] = bb[1] + d2; // bx, by
701  bb[6] = bb[4] - d2;
702  bb[7] = bb[5] + d1; // dx, dy
703  bb[10] = bb[8] - d1;
704  bb[11] = bb[9] - d2; // fx, fy
705  bb[14] = bb[12] + d2;
706  bb[15] = bb[13] - d1; // hx, hy
707 
708  // adjust all points
709  for ( i = 0; i < 16; i += 4 )
710  {
711 
712  alpha_seg = (( i / 4 > 0 ? ( i / 4 ) - 1 : 3 ) ) * M_PI / 2 + alpha;
713 
714  best_cp = DBL_MAX;
715  for ( j = 0; j < nbPoints; j++ )
716  {
717  cp = cross_product( bb[i+2], bb[i+3], bb[i], bb[i+1], x[cHull[j]], y[cHull[j]] );
718  if ( cp < best_cp )
719  {
720  best_cp = cp;
721  }
722  }
723 
724  distNearestPoint = best_cp / dref;
725 
726  d1 = cos( alpha_seg ) * distNearestPoint;
727  d2 = sin( alpha_seg ) * distNearestPoint;
728 
729  bb[i] += d1; // x
730  bb[i+1] += d2; // y
731  bb[i+2] += d1; // x
732  bb[i+3] += d2; // y
733  }
734 
735  // compute and compare AREA
736  width = cross_product( bb[6], bb[7], bb[4], bb[5], bb[12], bb[13] ) / dref;
737  length = cross_product( bb[2], bb[3], bb[0], bb[1], bb[8], bb[9] ) / dref;
738 
739  area = width * length;
740 
741  if ( area < 0 )
742  area *= -1;
743 
744 
745  if ( best_area - area > EPSILON )
746  {
747  best_area = area;
748  best_length = length;
749  best_width = width;
750  best_alpha = alpha;
751  memcpy( best_bb, bb, sizeof( double ) *16 );
752  }
753  }
754 
755  // best bbox is defined
756 
757  CHullBox * finalBb = new CHullBox();
758 
759  for ( i = 0; i < 16; i = i + 4 )
760  {
761  computeLineIntersection( best_bb[i], best_bb[i+1], best_bb[i+2], best_bb[i+3],
762  best_bb[( i+4 ) %16], best_bb[( i+5 ) %16], best_bb[( i+6 ) %16], best_bb[( i+7 ) %16],
763  &finalBb->x[int ( i/4 )], &finalBb->y[int ( i/4 )] );
764  }
765 
766  finalBb->alpha = best_alpha;
767  finalBb->width = best_width;
768  finalBb->length = best_length;
769 
770 #ifdef _DEBUG_FULL_
771  std::cout << "FINAL" << std::endl;
772  std::cout << "Length : " << best_length << std::endl;
773  std::cout << "Width : " << best_width << std::endl;
774  std::cout << "Alpha: " << best_alpha << " " << best_alpha*180 / M_PI << std::endl;
775  for ( i = 0; i < 4; i++ )
776  {
777  std::cout << finalBb->x[0] << " " << finalBb->y[0] << " ";
778  }
779  std::cout << std::endl;
780 #endif
781 
782  return finalBb;
783  }
784 
785 #if 0
786  double PointSet::getDistInside( double px, double py )
787  {
788 
789  double dist[8];
790  double rpx[8];
791  double rpy[8];
792  bool ok[8];
793 
794  if ( !isPointInPolygon( nbPoints, x, y, px, py ) )
795  {
796  double d = getDist( px, py );
797  //std::cout << "Outside : " << d << std::endl;
798  if ( d < 0 )
799  {
800  d = -( d * d * d * d );
801  }
802  else
803  {
804  d = d * d * d * d;
805  }
806  return d;
807  }
808 
809  int i;
810 
811  double width = ( xmax - xmin ) * 2;
812  double height = ( ymax - ymin ) * 2;
813 
814  /*
815  1 0 7
816  \ | /
817  2 --x -- 6
818  / | \
819  3 4 5
820  */
821 
822  // Compute references points
823  for ( i = 0; i < 8; i++ )
824  {
825  dist[i] = DBL_MAX;
826  ok[i] = false;
827  rpx[i] = px;
828  rpy[i] = py;
829  }
830 
831  rpx[0] += 0;
832  rpy[0] += height;
833 
834  rpx[1] -= width;
835  rpy[1] += height;
836 
837  rpx[2] -= width;
838  rpy[2] += 0;
839 
840  rpx[3] -= width;
841  rpy[3] -= height;
842 
843  rpx[4] += 0;
844  rpy[4] -= height;
845 
846  rpx[5] += width;
847  rpy[5] -= height;
848 
849  rpx[6] += width;
850  rpy[6] += 0;
851 
852  rpx[7] += width;
853  rpy[7] += height;
854 
855  int j, k;
856  for ( i = 0; i < nbPoints; i++ )
857  {
858  j = ( i + 1 ) % nbPoints;
859 
860  for ( k = 0; k < 8; k++ )
861  {
862  double ix, iy;
863  if ( computeSegIntersection( px, py, rpx[k], rpy[k], x[i], y[i], x[j], y[j], &ix, &iy ) )
864  {
865  double d = dist_euc2d_sq( px, py, ix, iy );
866  if ( dist[k] > d )
867  {
868  dist[k] = d;
869  ok[k] = true;
870  //std::cout << "new dist for " << k << ": " << dist[k] << std::endl;
871  }
872  }
873  }
874  }
875 
876  double a, b, c, d;
877 
878 
879  for ( i = 0; i < 8; i++ )
880  {
881  if ( !ok[i] )
882  {
883  std::cout << "ERROR!!!!!!!!!!!!!!!!!" << std::endl;
884  dist[i] = 0;
885  }
886  //std::cout << "dist[" << i << "]: " << dist[i] << std::endl;
887  }
888 
889  a = min( dist[0], dist[4] );
890  b = min( dist[1], dist[5] );
891  c = min( dist[2], dist[6] );
892  d = min( dist[3], dist[7] );
893  /*
894  std::cout << "a: " << a << std::endl;
895  std::cout << "b: " << b << std::endl;
896  std::cout << "c: " << c << std::endl;
897  std::cout << "d: " << d << std::endl;
898  */
899  //a = (a+b+c+d)/4.0;
900 
901  //a = min(a,b);
902  //c = min(c,d);
903  //return min(a,c);
904 
905 
906  return ( a*b*c*d );
907  }
908 #endif
909 
910  double PointSet::getDist( double px, double py, double *rx, double *ry )
911  {
912  if ( nbPoints == 1 || type == GEOS_POINT )
913  {
914  if ( rx && ry )
915  {
916  *rx = x[0];
917  *ry = y[0];
918  }
919  return dist_euc2d_sq( x[0], y[0], px, py );
920  }
921 
922  int a, b;
923  int nbP = ( type == GEOS_POLYGON ? nbPoints : nbPoints - 1 );
924 
925  double best_dist = DBL_MAX;
926  double d;
927 
928  for ( a = 0; a < nbP; a++ )
929  {
930  b = ( a + 1 ) % nbPoints;
931 
932  double px2, py2;
933  px2 = px - y[b] + y[a];
934  py2 = py + x[b] - x[a];
935  double ix, iy;
936 
937  // (px,py)->(px2,py2) is a line perpendicular to a->b
938  // Check the line p->p2 cross the segment a->b
939  if ( computeLineSegIntersection( px, py, px2, py2,
940  x[a], y[a], x[b], y[b],
941  &ix, &iy ) )
942  {
943  d = dist_euc2d_sq( px, py, ix, iy );
944  }
945  else
946  {
947  double d1 = dist_euc2d_sq( x[a], y[a], px, py );
948  double d2 = dist_euc2d_sq( x[b], y[b], px, py );
949  if ( d1 < d2 )
950  {
951  d = d1;
952  ix = x[a];
953  iy = y[a];
954  }
955  else
956  {
957  d = d2;
958  ix = x[b];
959  iy = y[b];
960  }
961  }
962 
963  if ( d < best_dist )
964  {
965  best_dist = d;
966  if ( rx && ry )
967  {
968  *rx = ix;
969  *ry = iy;
970  }
971  }
972  } // end for (a in nbPoints)
973 
974  return best_dist;
975  }
976 
977 
978 
979  void PointSet::getCentroid( double &px, double &py, bool forceInside )
980  {
981  // for explanation see this page:
982  // http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
983 
984  int i, j;
985  double cx = 0, cy = 0, A = 0, tmp, sumx = 0, sumy = 0;
986  for ( i = 0; i < nbPoints; i++ )
987  {
988  j = i + 1; if ( j == nbPoints ) j = 0;
989  tmp = (( x[i] - x[0] ) * ( y[j] - y[0] ) - ( x[j] - x[0] ) * ( y[i] - y[0] ) );
990  cx += ( x[i] + x[j] - 2 * x[0] ) * tmp;
991  cy += ( y[i] + y[j] - 2 * y[0] ) * tmp;
992  A += tmp;
993  sumx += x[i];
994  sumy += y[i];
995  }
996 
997  if ( A == 0 )
998  {
999  px = sumx / nbPoints;
1000  py = sumy / nbPoints;
1001  }
1002  else
1003  {
1004  px = cx / ( 3 * A ) + x[0];
1005  py = cy / ( 3 * A ) + y[0];
1006  }
1007 
1008  // check if centroid inside in polygon
1009  if ( forceInside && !isPointInPolygon( nbPoints, x, y, px, py ) )
1010  {
1011  GEOSContextHandle_t geosctxt = geosContext();
1012  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, nbPoints, 2 );
1013 
1014  for ( int i = 0; i < nbPoints; ++i )
1015  {
1016  GEOSCoordSeq_setX_r( geosctxt, coord, i, x[i] );
1017  GEOSCoordSeq_setY_r( geosctxt, coord, i, y[i] );
1018  }
1019 
1020  GEOSGeometry *geom = GEOSGeom_createPolygon_r( geosctxt, GEOSGeom_createLinearRing_r( geosctxt, coord ), 0, 0 );
1021 
1022  if ( geom )
1023  {
1024  GEOSGeometry *pointGeom = GEOSPointOnSurface_r( geosctxt, geom );
1025 
1026  if ( pointGeom )
1027  {
1028  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom );
1029  GEOSCoordSeq_getX_r( geosctxt, coordSeq, 0, &px );
1030  GEOSCoordSeq_getY_r( geosctxt, coordSeq, 0, &py );
1031 
1032  GEOSGeom_destroy_r( geosctxt, pointGeom );
1033  }
1034  GEOSGeom_destroy_r( geosctxt, geom );
1035  }
1036  }
1037  }
1038 
1039 } // end namespace
1040 
1041 #endif