@@ -66,7 +66,9 @@ QgsLabel::~QgsLabel()
66
66
QString QgsLabel::fieldValue ( int attr, QgsFeature *feature )
67
67
{
68
68
if ( mLabelField [attr].isEmpty () )
69
+ {
69
70
return QString ();
71
+ }
70
72
71
73
std::vector<QgsFeatureAttribute> fields = feature->attributeMap ();
72
74
@@ -94,15 +96,14 @@ void QgsLabel::renderLabel( QPainter * painter, QgsRect *viewExtent,
94
96
QFont font;
95
97
QString value;
96
98
QString text;
97
- double scale, x1, x2;
98
99
99
100
/* Calc scale (not nice) */
100
101
QgsPoint point;
101
102
point = transform->transform ( 0 , 0 );
102
- x1 = point.x ();
103
+ double x1 = point.x ();
103
104
point = transform->transform ( 1000 , 0 );
104
- x2 = point.x ();
105
- scale = (x2-x1)/ 1000 ;
105
+ double x2 = point.x ();
106
+ double scale = (x2-x1)* 0.001 ;
106
107
107
108
/* Text */
108
109
value = fieldValue ( Text, feature );
@@ -184,84 +185,22 @@ void QgsLabel::renderLabel( QPainter * painter, QgsRect *viewExtent,
184
185
font.setUnderline ( (bool ) value.toInt () );
185
186
}
186
187
187
-
188
- /* Coordinates */
189
- double x, y, xoffset, yoffset, ang;
190
-
191
- point = labelPoint ( feature );
192
-
188
+ //
189
+ QgsPoint overridePoint;
190
+ bool useOverridePoint = false ;
193
191
value = fieldValue ( XCoordinate, feature );
194
192
if ( !value.isEmpty () )
195
193
{
196
- point.setX ( value.toDouble () );
194
+ overridePoint.setX ( value.toDouble () );
195
+ useOverridePoint = true ;
197
196
}
198
197
value = fieldValue ( YCoordinate, feature );
199
198
if ( !value.isEmpty () )
200
199
{
201
- point.setY ( value.toDouble () );
202
- }
203
-
204
- // Convert point to projected units
205
- if (doCoordTransform)
206
- {
207
- try
208
- {
209
- point = (const_cast <QgsCoordinateTransform&>(coordTransform)).transform (point);
210
- }
211
- catch (QgsCsException &cse)
212
- {
213
- #ifdef QGISDEBUG
214
- std::cout << " Caught transform error in QgsLabel::renderLabel(). "
215
- << " Skipping rendering this label" << std::endl;
216
- #endif
217
- return ;
218
- }
219
- }
220
- // and then to canvas units
221
- transform->transform (&point);
222
- x = point.x ();
223
- y = point.y ();
224
-
225
- value = fieldValue ( XOffset, feature );
226
- if ( value.isEmpty () )
227
- {
228
- xoffset = mLabelAttributes ->xOffset ();
229
- }
230
- else
231
- {
232
- xoffset = value.toDouble ();
233
- }
234
- value = fieldValue ( YOffset, feature );
235
- if ( value.isEmpty () )
236
- {
237
- yoffset = mLabelAttributes ->yOffset ();
238
- }
239
- else
240
- {
241
- yoffset = value.toDouble ();
200
+ overridePoint.setY ( value.toDouble () );
201
+ useOverridePoint = true ;
242
202
}
243
203
244
- // recalc offset to points
245
- if ( mLabelAttributes ->offsetType () == QgsLabelAttributes::MapUnits )
246
- {
247
- xoffset *= scale;
248
- yoffset *= scale;
249
- }
250
-
251
- value = fieldValue ( Angle, feature );
252
- if ( value.isEmpty () )
253
- {
254
- ang = mLabelAttributes ->angle ();
255
- }
256
- else
257
- {
258
- ang = value.toDouble ();
259
- }
260
- double rad = ang * M_PI/180 ;
261
-
262
- x = x + xoffset * cos (rad) - yoffset * sin (rad);
263
- y = y - xoffset * sin (rad) - yoffset * cos (rad);
264
-
265
204
/* Alignment */
266
205
int alignment;
267
206
QFontMetrics fm ( font );
@@ -322,6 +261,105 @@ void QgsLabel::renderLabel( QPainter * painter, QgsRect *viewExtent,
322
261
dy = height;
323
262
}
324
263
264
+ // Offset
265
+ double xoffset, yoffset;
266
+ value = fieldValue ( XOffset, feature );
267
+ if ( value.isEmpty () )
268
+ {
269
+ xoffset = mLabelAttributes ->xOffset ();
270
+ }
271
+ else
272
+ {
273
+ xoffset = value.toDouble ();
274
+ }
275
+ value = fieldValue ( YOffset, feature );
276
+ if ( value.isEmpty () )
277
+ {
278
+ yoffset = mLabelAttributes ->yOffset ();
279
+ }
280
+ else
281
+ {
282
+ yoffset = value.toDouble ();
283
+ }
284
+
285
+ // recalc offset to points
286
+ if ( mLabelAttributes ->offsetType () == QgsLabelAttributes::MapUnits )
287
+ {
288
+ xoffset *= scale;
289
+ yoffset *= scale;
290
+ }
291
+
292
+ // Angle
293
+ double ang;
294
+ value = fieldValue ( Angle, feature );
295
+ if ( value.isEmpty () )
296
+ {
297
+ ang = mLabelAttributes ->angle ();
298
+ }
299
+ else
300
+ {
301
+ ang = value.toDouble ();
302
+ }
303
+
304
+
305
+ // Work out a suitable position to put the label for the
306
+ // feature. For multi-geometries, put the same label on each
307
+ // part.
308
+ if (useOverridePoint)
309
+ {
310
+ renderLabel (painter, overridePoint, doCoordTransform, coordTransform,
311
+ transform, text, font, pen, dx, dy,
312
+ xoffset, yoffset, ang);
313
+ }
314
+ else
315
+ {
316
+ std::vector<QgsPoint> points;
317
+ labelPoint ( points, feature );
318
+ for (int i = 0 ; i < points.size (); ++i)
319
+ {
320
+ renderLabel (painter, points[i], doCoordTransform, coordTransform,
321
+ transform, text, font, pen, dx, dy,
322
+ xoffset, yoffset, ang);
323
+ }
324
+ }
325
+ }
326
+
327
+ void QgsLabel::renderLabel (QPainter* painter, QgsPoint point,
328
+ bool doCoordTransform,
329
+ const QgsCoordinateTransform& coordTransform,
330
+ QgsMapToPixel* transform,
331
+ QString text, QFont font, QPen pen,
332
+ int dx, int dy,
333
+ double xoffset, double yoffset,
334
+ double ang)
335
+ {
336
+ // Convert point to projected units
337
+ if (doCoordTransform)
338
+ {
339
+ try
340
+ {
341
+ point = (const_cast <QgsCoordinateTransform&>(coordTransform)).transform (point);
342
+ }
343
+ catch (QgsCsException &cse)
344
+ {
345
+ #ifdef QGISDEBUG
346
+ std::cout << " Caught transform error in QgsLabel::renderLabel(). "
347
+ << " Skipping rendering this label" << std::endl;
348
+ #endif
349
+ return ;
350
+ }
351
+ }
352
+
353
+ // and then to canvas units
354
+ transform->transform (&point);
355
+ double x = point.x ();
356
+ double y = point.y ();
357
+
358
+ static const double rad = ang * M_PI/180 ;
359
+
360
+ x = x + xoffset * cos (rad) - yoffset * sin (rad);
361
+ y = y - xoffset * sin (rad) - yoffset * cos (rad);
362
+
325
363
painter->save ();
326
364
painter->setFont ( font );
327
365
painter->translate ( x, y );
@@ -348,6 +386,7 @@ void QgsLabel::renderLabel( QPainter * painter, QgsRect *viewExtent,
348
386
}
349
387
}
350
388
}
389
+
351
390
painter->setPen ( pen );
352
391
painter->drawText ( dx, dy, text );
353
392
painter->restore ();
@@ -415,32 +454,69 @@ QgsLabelAttributes *QgsLabel::layerAttributes ( void )
415
454
return mLabelAttributes ;
416
455
}
417
456
418
- QgsPoint QgsLabel::labelPoint ( QgsFeature *feature )
457
+ void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature *feature )
419
458
{
459
+ unsigned char *geom = feature->getGeometry ();
460
+ int wkbType;
461
+ memcpy (&wkbType, (geom+1 ), sizeof (wkbType));
462
+
463
+ QgsPoint point;
464
+
465
+ switch (wkbType)
466
+ {
467
+ case QGis::WKBPoint:
468
+ case QGis::WKBLineString:
469
+ case QGis::WKBPolygon:
470
+ labelPoint (point, geom);
471
+ points.push_back (point);
472
+ break ;
473
+ case QGis::WKBMultiPoint:
474
+ case QGis::WKBMultiLineString:
475
+ case QGis::WKBMultiPolygon:
476
+ // Return a position for each individual in the multi-feature
477
+ int numFeatures = (int )(*(geom + 5 ));
478
+ geom += 9 ; // now points to start of array of WKB's
479
+ for (int i = 0 ; i < numFeatures; ++i)
480
+ {
481
+ geom = labelPoint (point, geom);
482
+ points.push_back (point);
483
+ }
484
+ break ;
485
+ default :
486
+ std::cerr << " Unknown geometry type of " << wkbType << ' \n ' ;
487
+ }
488
+ }
489
+
490
+ unsigned char * QgsLabel::labelPoint ( QgsPoint& point, unsigned char * geom)
491
+ {
492
+ // Number of bytes that ints and doubles take in the WKB format.
493
+ static const unsigned int sizeOfInt = 4 ;
494
+ static const unsigned int sizeOfDouble = 8 ;
495
+
420
496
int wkbType;
421
497
double *x, *y;
422
498
unsigned char *ptr;
423
499
int *nPoints;
424
-
425
- unsigned char *geom = feature->getGeometry ();
500
+ // Upon return from this function, this variable will contain a
501
+ // pointer to the first byte beyond the current feature.
502
+ unsigned char *nextFeature = geom;
426
503
427
504
memcpy (&wkbType, (geom+1 ), sizeof (wkbType));
428
505
429
- QgsPoint point;
430
-
431
506
switch (wkbType)
432
507
{
433
508
case QGis::WKBPoint:
434
- x = (double *) (geom + 5 );
435
- y = (double *) (geom + 5 + sizeof (double ));
436
- point.setX (*x);
437
- point. setY (*y) ;
438
- break ;
509
+ x = (double *) (geom + 5 );
510
+ y = (double *) (geom + 5 + sizeof (double ));
511
+ point.set (*x, *y );
512
+ nextFeature += 1 + sizeOfInt + sizeOfDouble* 2 ;
513
+ break ;
439
514
440
515
case QGis::WKBLineString: // Line center
441
516
double dx, dy, tl, l;
442
517
ptr = geom + 5 ;
443
518
nPoints = (int *)ptr;
519
+ nextFeature += 1 + sizeOfInt*2 + (*nPoints)*sizeOfDouble*2 ;
444
520
ptr = geom + 1 + 2 * sizeof (int );
445
521
446
522
tl = 0 ;
@@ -479,7 +555,6 @@ QgsPoint QgsLabel::labelPoint ( QgsFeature *feature )
479
555
ptr = geom + 1 + 2 * sizeof (int ); // set pointer to the first ring
480
556
nPoints = (int *) ptr;
481
557
ptr += 4 ;
482
-
483
558
sx = sy = 0 ;
484
559
for (int i = 0 ; i < *nPoints-1 ; i++)
485
560
{
@@ -488,77 +563,25 @@ QgsPoint QgsLabel::labelPoint ( QgsFeature *feature )
488
563
}
489
564
point.setX ( sx/(*nPoints-1 ) );
490
565
point.setY ( sy/(*nPoints-1 ) );
491
-
492
- break ;
493
- case QGis::WKBMultiPolygon:
494
- break ; // /// <--------------remove this when code below needs testing..........
566
+ // Work out a pointer to the next feature after this one.
567
+ int numRings = ( int )(*(geom+ 1 +sizeOfInt)) ;
568
+ unsigned char * nextRing = nextFeature + 1 + 2 *sizeOfInt;
569
+ for ( int i = 0 ; i < numRings; ++i)
495
570
{
496
- double sx, sy;
497
- unsigned char *ptr;
498
- int idx, kdx;
499
- int *numPolygons, *numRings;
500
-
501
- // get the number of polygons
502
- ptr = geom + 5 ;
503
- numPolygons = (int *) ptr;
504
- #ifdef QGISDEBUG
505
-
506
- std::cout << " Finding label point for mutipolygon with "
507
- << *numPolygons << " parts " << std::endl;
508
- #endif
509
- // for (kdx = 0; kdx < *numPolygons; kdx++)
510
- for (kdx = 0 ; kdx < 1 ; kdx++) // just label the first sub polygon
511
- {
512
- // skip the endian and feature type info and
513
- // get number of rings in the polygon
514
- ptr+=14 ;
515
- numRings = (int *) ptr;
516
- ptr += 4 ;
517
- #ifdef QGISDEBUG
518
-
519
- std::cout << " Multipolygon part " << kdx << " ring iteration " << std::endl;
520
- #endif
521
-
522
- for (idx = 0 ; idx < *numRings; idx++)
523
- {
524
- #ifdef QGISDEBUG
525
- std::cout << " Multipolygon part " << kdx << " ring " << idx
526
- << std::endl;
527
- #endif
528
- // get number of points in the ring
529
- nPoints = (int *) ptr;
530
- ptr += 4 ;
531
- sx = sy = 0 ;
532
-
533
- // loop through vertices skipping last which == first
534
- for (int i = 0 ; i < *nPoints-1 ; i++)
535
- {
536
- x = (double *)ptr;
537
- ptr += sizeof (double );
538
- y = (double *)ptr;
539
- ptr += sizeof (double );
540
- sx += *x;
541
- sy += *y;
542
- #ifdef QGISDEBUG
543
-
544
- std::cout << " \t Vertex " << i << " x: " << *x << " y: " << *y << std::endl;
545
- #endif
546
-
547
- }
548
- }
549
- #ifdef QGISDEBUG
550
- std::cout << " Setting multipart polygon label point to" << sx/(*nPoints-1 ) << " , " << sy/(*nPoints-1 ) << std::endl;
551
- #endif
552
-
553
- point.setX ( sx/(*nPoints-1 ) );
554
- point.setY ( sy/(*nPoints-1 ) );
555
- }
556
- break ;
571
+ int numPoints = (int )(*nextRing);
572
+ // get the start of the next ring
573
+ nextRing += sizeOfInt + numPoints*sizeOfDouble*2 ;
574
+ }
575
+ nextFeature = nextRing;
557
576
577
+ break ;
558
578
559
- }
579
+ default :
580
+ // To get here is a bug because our caller should be filtering
581
+ // on wkb type.
582
+ break ;
560
583
}
561
- return QgsPoint ( point ) ;
584
+ return nextFeature ;
562
585
}
563
586
564
587
void QgsLabel::readXML ( const QDomNode& node )
0 commit comments