Branch data Line data Source code
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 "layer.h"
31 : : #include "pal.h"
32 : : #include "costcalculator.h"
33 : : #include "feature.h"
34 : : #include "geomfunction.h"
35 : : #include "labelposition.h"
36 : : #include "qgsgeos.h"
37 : : #include "qgsmessagelog.h"
38 : : #include <cmath>
39 : : #include <cfloat>
40 : :
41 : : using namespace pal;
42 : :
43 : 0 : LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed, Quadrant quadrant )
44 : 0 : : id( id )
45 : 0 : , feature( feature )
46 : 0 : , probFeat( 0 )
47 : 0 : , nbOverlap( 0 )
48 : 0 : , alpha( alpha )
49 : 0 : , w( w )
50 : 0 : , h( h )
51 : 0 : , partId( -1 )
52 : 0 : , reversed( isReversed )
53 : 0 : , upsideDown( false )
54 : 0 : , quadrant( quadrant )
55 : 0 : , mCost( cost )
56 : 0 : , mHasObstacleConflict( false )
57 : 0 : , mUpsideDownCharCount( 0 )
58 : 0 : {
59 : 0 : type = GEOS_POLYGON;
60 : 0 : nbPoints = 4;
61 : 0 : x.resize( nbPoints );
62 : 0 : y.resize( nbPoints );
63 : :
64 : : // alpha take his value bw 0 and 2*pi rad
65 : 0 : while ( this->alpha > 2 * M_PI )
66 : 0 : this->alpha -= 2 * M_PI;
67 : :
68 : 0 : while ( this->alpha < 0 )
69 : 0 : this->alpha += 2 * M_PI;
70 : :
71 : 0 : double beta = this->alpha + M_PI_2;
72 : :
73 : : double dx1, dx2, dy1, dy2;
74 : :
75 : 0 : dx1 = std::cos( this->alpha ) * w;
76 : 0 : dy1 = std::sin( this->alpha ) * w;
77 : :
78 : 0 : dx2 = std::cos( beta ) * h;
79 : 0 : dy2 = std::sin( beta ) * h;
80 : :
81 : 0 : x[0] = x1;
82 : 0 : y[0] = y1;
83 : :
84 : 0 : x[1] = x1 + dx1;
85 : 0 : y[1] = y1 + dy1;
86 : :
87 : 0 : x[2] = x1 + dx1 + dx2;
88 : 0 : y[2] = y1 + dy1 + dy2;
89 : :
90 : 0 : x[3] = x1 + dx2;
91 : 0 : y[3] = y1 + dy2;
92 : :
93 : : // upside down ? (curved labels are always correct)
94 : 0 : if ( !feature->layer()->isCurved() &&
95 : 0 : this->alpha > M_PI_2 && this->alpha <= 3 * M_PI_2 )
96 : : {
97 : 0 : if ( feature->onlyShowUprightLabels() )
98 : : {
99 : : // Turn label upsidedown by inverting boundary points
100 : : double tx, ty;
101 : :
102 : 0 : tx = x[0];
103 : 0 : ty = y[0];
104 : :
105 : 0 : x[0] = x[2];
106 : 0 : y[0] = y[2];
107 : :
108 : 0 : x[2] = tx;
109 : 0 : y[2] = ty;
110 : :
111 : 0 : tx = x[1];
112 : 0 : ty = y[1];
113 : :
114 : 0 : x[1] = x[3];
115 : 0 : y[1] = y[3];
116 : :
117 : 0 : x[3] = tx;
118 : 0 : y[3] = ty;
119 : :
120 : 0 : if ( this->alpha < M_PI )
121 : 0 : this->alpha += M_PI;
122 : : else
123 : 0 : this->alpha -= M_PI;
124 : :
125 : : // labels with text shown upside down are not classified as upsideDown,
126 : : // only those whose boundary points have been inverted
127 : 0 : upsideDown = true;
128 : 0 : }
129 : 0 : }
130 : :
131 : 0 : for ( int i = 0; i < nbPoints; ++i )
132 : : {
133 : 0 : xmin = std::min( xmin, x[i] );
134 : 0 : xmax = std::max( xmax, x[i] );
135 : 0 : ymin = std::min( ymin, y[i] );
136 : 0 : ymax = std::max( ymax, y[i] );
137 : 0 : }
138 : 0 : }
139 : :
140 : 0 : LabelPosition::LabelPosition( const LabelPosition &other )
141 : 0 : : PointSet( other )
142 : 0 : {
143 : 0 : id = other.id;
144 : 0 : mCost = other.mCost;
145 : 0 : feature = other.feature;
146 : 0 : probFeat = other.probFeat;
147 : 0 : nbOverlap = other.nbOverlap;
148 : :
149 : 0 : alpha = other.alpha;
150 : 0 : w = other.w;
151 : 0 : h = other.h;
152 : :
153 : 0 : if ( other.mNextPart )
154 : 0 : mNextPart = std::make_unique< LabelPosition >( *other.mNextPart );
155 : :
156 : 0 : partId = other.partId;
157 : 0 : upsideDown = other.upsideDown;
158 : 0 : reversed = other.reversed;
159 : 0 : quadrant = other.quadrant;
160 : 0 : mHasObstacleConflict = other.mHasObstacleConflict;
161 : 0 : mUpsideDownCharCount = other.mUpsideDownCharCount;
162 : 0 : }
163 : :
164 : 0 : bool LabelPosition::isIn( double *bbox )
165 : : {
166 : : int i;
167 : :
168 : 0 : for ( i = 0; i < 4; i++ )
169 : : {
170 : 0 : if ( x[i] >= bbox[0] && x[i] <= bbox[2] &&
171 : 0 : y[i] >= bbox[1] && y[i] <= bbox[3] )
172 : 0 : return true;
173 : 0 : }
174 : :
175 : 0 : if ( mNextPart )
176 : 0 : return mNextPart->isIn( bbox );
177 : : else
178 : 0 : return false;
179 : 0 : }
180 : :
181 : 0 : bool LabelPosition::isIntersect( double *bbox )
182 : : {
183 : : int i;
184 : :
185 : 0 : for ( i = 0; i < 4; i++ )
186 : : {
187 : 0 : if ( x[i] >= bbox[0] && x[i] <= bbox[2] &&
188 : 0 : y[i] >= bbox[1] && y[i] <= bbox[3] )
189 : 0 : return true;
190 : 0 : }
191 : :
192 : 0 : if ( mNextPart )
193 : 0 : return mNextPart->isIntersect( bbox );
194 : : else
195 : 0 : return false;
196 : 0 : }
197 : :
198 : 0 : bool LabelPosition::intersects( const GEOSPreparedGeometry *geometry )
199 : : {
200 : 0 : if ( !mGeos )
201 : 0 : createGeosGeom();
202 : :
203 : : try
204 : : {
205 : 0 : if ( GEOSPreparedIntersects_r( QgsGeos::getGEOSHandler(), geometry, mGeos ) == 1 )
206 : : {
207 : 0 : return true;
208 : : }
209 : 0 : else if ( mNextPart )
210 : : {
211 : 0 : return mNextPart->intersects( geometry );
212 : : }
213 : 0 : }
214 : : catch ( GEOSException &e )
215 : : {
216 : 0 : qWarning( "GEOS exception: %s", e.what() );
217 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
218 : 0 : return false;
219 : 0 : }
220 : :
221 : 0 : return false;
222 : 0 : }
223 : :
224 : 0 : bool LabelPosition::within( const GEOSPreparedGeometry *geometry )
225 : : {
226 : 0 : if ( !mGeos )
227 : 0 : createGeosGeom();
228 : :
229 : : try
230 : : {
231 : 0 : if ( GEOSPreparedContains_r( QgsGeos::getGEOSHandler(), geometry, mGeos ) != 1 )
232 : : {
233 : 0 : return false;
234 : : }
235 : 0 : else if ( mNextPart )
236 : : {
237 : 0 : return mNextPart->within( geometry );
238 : : }
239 : 0 : }
240 : : catch ( GEOSException &e )
241 : : {
242 : 0 : qWarning( "GEOS exception: %s", e.what() );
243 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
244 : 0 : return false;
245 : 0 : }
246 : :
247 : 0 : return true;
248 : 0 : }
249 : :
250 : 0 : bool LabelPosition::isInside( double *bbox )
251 : : {
252 : 0 : for ( int i = 0; i < 4; i++ )
253 : : {
254 : 0 : if ( !( x[i] >= bbox[0] && x[i] <= bbox[2] &&
255 : 0 : y[i] >= bbox[1] && y[i] <= bbox[3] ) )
256 : 0 : return false;
257 : 0 : }
258 : :
259 : 0 : if ( mNextPart )
260 : 0 : return mNextPart->isInside( bbox );
261 : : else
262 : 0 : return true;
263 : 0 : }
264 : :
265 : 0 : bool LabelPosition::isInConflict( const LabelPosition *lp ) const
266 : : {
267 : 0 : if ( this->probFeat == lp->probFeat ) // bugfix #1
268 : 0 : return false; // always overlaping itself !
269 : :
270 : 0 : if ( !nextPart() && !lp->nextPart() )
271 : : {
272 : 0 : if ( qgsDoubleNear( alpha, 0 ) && qgsDoubleNear( lp->alpha, 0 ) )
273 : : {
274 : : // simple case -- both candidates are oriented to axis, so shortcut with easy calculation
275 : 0 : return boundingBoxIntersects( lp );
276 : : }
277 : 0 : }
278 : :
279 : 0 : return isInConflictMultiPart( lp );
280 : 0 : }
281 : :
282 : 0 : bool LabelPosition::isInConflictMultiPart( const LabelPosition *lp ) const
283 : : {
284 : 0 : if ( !mMultipartGeos )
285 : 0 : createMultiPartGeosGeom();
286 : :
287 : 0 : if ( !lp->mMultipartGeos )
288 : 0 : lp->createMultiPartGeosGeom();
289 : :
290 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
291 : : try
292 : : {
293 : 0 : bool result = ( GEOSPreparedIntersects_r( geosctxt, preparedMultiPartGeom(), lp->mMultipartGeos ) == 1 );
294 : 0 : return result;
295 : 0 : }
296 : : catch ( GEOSException &e )
297 : : {
298 : 0 : qWarning( "GEOS exception: %s", e.what() );
299 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
300 : 0 : return false;
301 : 0 : }
302 : :
303 : 0 : return false;
304 : 0 : }
305 : :
306 : 0 : int LabelPosition::partCount() const
307 : : {
308 : 0 : if ( mNextPart )
309 : 0 : return mNextPart->partCount() + 1;
310 : : else
311 : 0 : return 1;
312 : 0 : }
313 : :
314 : 0 : void LabelPosition::offsetPosition( double xOffset, double yOffset )
315 : : {
316 : 0 : for ( int i = 0; i < 4; i++ )
317 : : {
318 : 0 : x[i] += xOffset;
319 : 0 : y[i] += yOffset;
320 : 0 : }
321 : :
322 : 0 : if ( mNextPart )
323 : 0 : mNextPart->offsetPosition( xOffset, yOffset );
324 : :
325 : 0 : invalidateGeos();
326 : 0 : }
327 : :
328 : 0 : int LabelPosition::getId() const
329 : : {
330 : 0 : return id;
331 : : }
332 : :
333 : 0 : double LabelPosition::getX( int i ) const
334 : : {
335 : 0 : return ( i >= 0 && i < 4 ? x[i] : -1 );
336 : : }
337 : :
338 : 0 : double LabelPosition::getY( int i ) const
339 : : {
340 : 0 : return ( i >= 0 && i < 4 ? y[i] : -1 );
341 : : }
342 : :
343 : 0 : double LabelPosition::getAlpha() const
344 : : {
345 : 0 : return alpha;
346 : : }
347 : :
348 : 0 : void LabelPosition::validateCost()
349 : : {
350 : 0 : if ( mCost >= 1 )
351 : : {
352 : 0 : mCost -= int ( mCost ); // label cost up to 1
353 : 0 : }
354 : 0 : }
355 : :
356 : 0 : FeaturePart *LabelPosition::getFeaturePart() const
357 : : {
358 : 0 : return feature;
359 : : }
360 : :
361 : 0 : void LabelPosition::getBoundingBox( double amin[2], double amax[2] ) const
362 : : {
363 : 0 : if ( mNextPart )
364 : : {
365 : 0 : mNextPart->getBoundingBox( amin, amax );
366 : 0 : }
367 : 0 : else
368 : : {
369 : 0 : amin[0] = std::numeric_limits<double>::max();
370 : 0 : amax[0] = std::numeric_limits<double>::lowest();
371 : 0 : amin[1] = std::numeric_limits<double>::max();
372 : 0 : amax[1] = std::numeric_limits<double>::lowest();
373 : : }
374 : 0 : for ( int c = 0; c < 4; c++ )
375 : : {
376 : 0 : if ( x[c] < amin[0] )
377 : 0 : amin[0] = x[c];
378 : 0 : if ( x[c] > amax[0] )
379 : 0 : amax[0] = x[c];
380 : 0 : if ( y[c] < amin[1] )
381 : 0 : amin[1] = y[c];
382 : 0 : if ( y[c] > amax[1] )
383 : 0 : amax[1] = y[c];
384 : 0 : }
385 : 0 : }
386 : :
387 : 0 : void LabelPosition::setConflictsWithObstacle( bool conflicts )
388 : : {
389 : 0 : mHasObstacleConflict = conflicts;
390 : 0 : if ( mNextPart )
391 : 0 : mNextPart->setConflictsWithObstacle( conflicts );
392 : 0 : }
393 : :
394 : 0 : void LabelPosition::setHasHardObstacleConflict( bool conflicts )
395 : : {
396 : 0 : mHasHardConflict = conflicts;
397 : 0 : if ( mNextPart )
398 : 0 : mNextPart->setHasHardObstacleConflict( conflicts );
399 : 0 : }
400 : :
401 : 0 : void LabelPosition::removeFromIndex( PalRtree<LabelPosition> &index )
402 : : {
403 : : double amin[2];
404 : : double amax[2];
405 : 0 : getBoundingBox( amin, amax );
406 : 0 : index.remove( this, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
407 : 0 : }
408 : :
409 : 0 : void LabelPosition::insertIntoIndex( PalRtree<LabelPosition> &index )
410 : : {
411 : : double amin[2];
412 : : double amax[2];
413 : 0 : getBoundingBox( amin, amax );
414 : 0 : index.insert( this, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
415 : 0 : }
416 : :
417 : :
418 : 0 : void LabelPosition::createMultiPartGeosGeom() const
419 : : {
420 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
421 : :
422 : 0 : std::vector< const GEOSGeometry * > geometries;
423 : 0 : const LabelPosition *tmp1 = this;
424 : 0 : while ( tmp1 )
425 : : {
426 : 0 : const GEOSGeometry *partGeos = tmp1->geos();
427 : 0 : if ( !GEOSisEmpty_r( geosctxt, partGeos ) )
428 : 0 : geometries.emplace_back( partGeos );
429 : 0 : tmp1 = tmp1->nextPart();
430 : : }
431 : :
432 : 0 : const std::size_t partCount = geometries.size();
433 : 0 : GEOSGeometry **geomarr = new GEOSGeometry*[ partCount ];
434 : 0 : for ( std::size_t i = 0; i < partCount; ++i )
435 : : {
436 : 0 : geomarr[i ] = GEOSGeom_clone_r( geosctxt, geometries[i] );
437 : 0 : }
438 : :
439 : 0 : mMultipartGeos = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOLYGON, geomarr, partCount );
440 : 0 : delete [] geomarr;
441 : 0 : }
442 : :
443 : 0 : const GEOSPreparedGeometry *LabelPosition::preparedMultiPartGeom() const
444 : : {
445 : 0 : if ( !mMultipartGeos )
446 : 0 : createMultiPartGeosGeom();
447 : :
448 : 0 : if ( !mMultipartPreparedGeos )
449 : : {
450 : 0 : mMultipartPreparedGeos = GEOSPrepare_r( QgsGeos::getGEOSHandler(), mMultipartGeos );
451 : 0 : }
452 : 0 : return mMultipartPreparedGeos;
453 : : }
454 : :
455 : 0 : double LabelPosition::getDistanceToPoint( double xp, double yp ) const
456 : : {
457 : : //first check if inside, if so then distance is -1
458 : 0 : bool contains = false;
459 : 0 : if ( alpha == 0 )
460 : : {
461 : : // easy case -- horizontal label
462 : 0 : contains = x[0] <= xp && x[1] >= xp && y[0] <= yp && y[2] >= yp;
463 : 0 : }
464 : : else
465 : : {
466 : 0 : contains = containsPoint( xp, yp );
467 : : }
468 : :
469 : 0 : double distance = -1;
470 : 0 : if ( !contains )
471 : : {
472 : 0 : if ( alpha == 0 )
473 : : {
474 : 0 : const double dx = std::max( std::max( x[0] - xp, 0.0 ), xp - x[1] );
475 : 0 : const double dy = std::max( std::max( y[0] - yp, 0.0 ), yp - y[2] );
476 : 0 : distance = std::sqrt( dx * dx + dy * dy );
477 : 0 : }
478 : : else
479 : : {
480 : 0 : distance = std::sqrt( minDistanceToPoint( xp, yp ) );
481 : : }
482 : 0 : }
483 : :
484 : 0 : if ( mNextPart && distance > 0 )
485 : 0 : return std::min( distance, mNextPart->getDistanceToPoint( xp, yp ) );
486 : :
487 : 0 : return distance;
488 : 0 : }
489 : :
490 : 0 : bool LabelPosition::crossesLine( PointSet *line ) const
491 : : {
492 : 0 : if ( !mGeos )
493 : 0 : createGeosGeom();
494 : :
495 : 0 : if ( !line->mGeos )
496 : 0 : line->createGeosGeom();
497 : :
498 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
499 : : try
500 : : {
501 : 0 : if ( GEOSPreparedIntersects_r( geosctxt, line->preparedGeom(), mGeos ) == 1 )
502 : : {
503 : 0 : return true;
504 : : }
505 : 0 : else if ( mNextPart )
506 : : {
507 : 0 : return mNextPart->crossesLine( line );
508 : : }
509 : 0 : }
510 : : catch ( GEOSException &e )
511 : : {
512 : 0 : qWarning( "GEOS exception: %s", e.what() );
513 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
514 : 0 : return false;
515 : 0 : }
516 : :
517 : 0 : return false;
518 : 0 : }
519 : :
520 : 0 : bool LabelPosition::crossesBoundary( PointSet *polygon ) const
521 : : {
522 : 0 : if ( !mGeos )
523 : 0 : createGeosGeom();
524 : :
525 : 0 : if ( !polygon->mGeos )
526 : 0 : polygon->createGeosGeom();
527 : :
528 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
529 : : try
530 : : {
531 : 0 : if ( GEOSPreparedIntersects_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1
532 : 0 : && GEOSPreparedContains_r( geosctxt, polygon->preparedGeom(), mGeos ) != 1 )
533 : : {
534 : 0 : return true;
535 : : }
536 : 0 : else if ( mNextPart )
537 : : {
538 : 0 : return mNextPart->crossesBoundary( polygon );
539 : : }
540 : 0 : }
541 : : catch ( GEOSException &e )
542 : : {
543 : 0 : qWarning( "GEOS exception: %s", e.what() );
544 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
545 : 0 : return false;
546 : 0 : }
547 : :
548 : 0 : return false;
549 : 0 : }
550 : :
551 : 0 : int LabelPosition::polygonIntersectionCost( PointSet *polygon ) const
552 : : {
553 : : //effectively take the average polygon intersection cost for all label parts
554 : 0 : double totalCost = polygonIntersectionCostForParts( polygon );
555 : 0 : int n = partCount();
556 : 0 : return std::ceil( totalCost / n );
557 : : }
558 : :
559 : 0 : bool LabelPosition::intersectsWithPolygon( PointSet *polygon ) const
560 : : {
561 : 0 : if ( !mGeos )
562 : 0 : createGeosGeom();
563 : :
564 : 0 : if ( !polygon->mGeos )
565 : 0 : polygon->createGeosGeom();
566 : :
567 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
568 : : try
569 : : {
570 : 0 : if ( GEOSPreparedIntersects_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 )
571 : : {
572 : 0 : return true;
573 : : }
574 : 0 : }
575 : : catch ( GEOSException &e )
576 : : {
577 : 0 : qWarning( "GEOS exception: %s", e.what() );
578 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
579 : 0 : }
580 : :
581 : 0 : if ( mNextPart )
582 : : {
583 : 0 : return mNextPart->intersectsWithPolygon( polygon );
584 : : }
585 : : else
586 : : {
587 : 0 : return false;
588 : : }
589 : 0 : }
590 : :
591 : 0 : double LabelPosition::polygonIntersectionCostForParts( PointSet *polygon ) const
592 : : {
593 : 0 : if ( !mGeos )
594 : 0 : createGeosGeom();
595 : :
596 : 0 : if ( !polygon->mGeos )
597 : 0 : polygon->createGeosGeom();
598 : :
599 : 0 : GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
600 : 0 : double cost = 0;
601 : : try
602 : : {
603 : 0 : if ( GEOSPreparedIntersects_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 )
604 : : {
605 : : //at least a partial intersection
606 : 0 : cost += 1;
607 : :
608 : : double px, py;
609 : :
610 : : // check each corner
611 : 0 : for ( int i = 0; i < 4; ++i )
612 : : {
613 : 0 : px = x[i];
614 : 0 : py = y[i];
615 : :
616 : 0 : for ( int a = 0; a < 2; ++a ) // and each middle of segment
617 : : {
618 : 0 : if ( polygon->containsPoint( px, py ) )
619 : 0 : cost++;
620 : 0 : px = ( x[i] + x[( i + 1 ) % 4] ) / 2.0;
621 : 0 : py = ( y[i] + y[( i + 1 ) % 4] ) / 2.0;
622 : 0 : }
623 : 0 : }
624 : :
625 : 0 : px = ( x[0] + x[2] ) / 2.0;
626 : 0 : py = ( y[0] + y[2] ) / 2.0;
627 : :
628 : : //check the label center. if covered by polygon, cost of 4
629 : 0 : if ( polygon->containsPoint( px, py ) )
630 : 0 : cost += 4;
631 : 0 : }
632 : 0 : }
633 : : catch ( GEOSException &e )
634 : : {
635 : 0 : qWarning( "GEOS exception: %s", e.what() );
636 : 0 : QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
637 : 0 : }
638 : :
639 : : //maintain scaling from 0 -> 12
640 : 0 : cost = 12.0 * cost / 13.0;
641 : :
642 : 0 : if ( mNextPart )
643 : : {
644 : 0 : cost += mNextPart->polygonIntersectionCostForParts( polygon );
645 : 0 : }
646 : :
647 : 0 : return cost;
648 : 0 : }
|