~ubuntu-branches/ubuntu/jaunty/mapserver/jaunty-updates

« back to all changes in this revision

Viewing changes to mapprimitive.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2006-11-02 11:44:17 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20061102114417-pnutjb20kqzl23ua
Tags: 4.10.0-3
debian/control: build-depends on libpq-dev. (Closes: #396565)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
 ******************************************************************************
28
28
 *
29
29
 * $Log: mapprimitive.c,v $
30
 
 * Revision 1.60.2.1  2006/02/17 03:06:13  sdlime
 
30
 * Revision 1.76  2006/09/01 18:03:19  umberto
 
31
 * Removed USE_GEOS defines, bug #1890
 
32
 *
 
33
 * Revision 1.75  2006/08/17 04:32:16  sdlime
 
34
 * Disable path following labels unless GD 2.0.29 or greater is available.
 
35
 *
 
36
 * Revision 1.74  2006/06/27 13:58:19  frank
 
37
 * Place shapeObj->geometry assignment into #ifdef USE_GEOS.
 
38
 *
 
39
 * Revision 1.73  2006/06/27 06:32:09  sdlime
 
40
 * Fixed msCopyShape to initialize the geometry property of the destination shape to NULL.
 
41
 *
 
42
 * Revision 1.72  2006/05/18 22:20:37  sdlime
 
43
 * Fixed offseting code percentage of 1.0 maps to width-1 or height-1.
 
44
 *
 
45
 * Revision 1.71  2006/04/28 03:13:02  sdlime
 
46
 * Fixed a few issues with relative coordinates. Added support for all nine relative positions. (bug 1547)
 
47
 *
 
48
 * Revision 1.70  2006/04/27 04:05:17  sdlime
 
49
 * Initial support for relative coordinates. (bug 1547)
 
50
 *
 
51
 * Revision 1.69  2006/04/26 13:42:53  frank
 
52
 * temporarily block out MS_PERCENTAGES use till it is defined.
 
53
 *
 
54
 * Revision 1.68  2006/04/26 03:25:47  sdlime
 
55
 * Applied most recent patch for curved labels. (bug 1620)
 
56
 *
 
57
 * Revision 1.67  2006/03/22 23:31:20  sdlime
 
58
 * Applied latest patch for curved labels. (bug 1620)
 
59
 *
 
60
 * Revision 1.66  2006/03/02 06:43:51  sdlime
 
61
 * Applied latest patch for curved labels. (bug 1620)
 
62
 *
 
63
 * Revision 1.65  2006/02/24 05:53:49  sdlime
 
64
 * Applied another round of patches for bug 1620.
 
65
 *
 
66
 * Revision 1.64  2006/02/18 21:14:09  hobu
 
67
 * INFINITY is already defined on in the math headers on osx.
 
68
 * Don't redefine it if it is already there.
 
69
 *
 
70
 * Revision 1.63  2006/02/18 20:59:13  sdlime
 
71
 * Initial code for curved labels. (bug 1620)
 
72
 *
 
73
 * Revision 1.62  2006/02/17 03:05:23  sdlime
 
74
 * Slightly more efficient version (no modulus operator) of the routine to test if a ring is an outer ring. (bug 1648)
 
75
 *
 
76
 * Revision 1.61  2006/02/16 07:51:31  sdlime
31
77
 * Fixed a flaw in routine that computes outer ring list. In certain cases it could miss an outer ring with holes in certain places. (bug 1648)
32
78
 *
33
79
 * Revision 1.60  2005/11/01 05:35:50  frank
96
142
#include "mapprimitive.h"
97
143
#include <assert.h>
98
144
 
99
 
MS_CVSID("$Id: mapprimitive.c,v 1.60.2.1 2006/02/17 03:06:13 sdlime Exp $")
 
145
MS_CVSID("$Id: mapprimitive.c,v 1.76 2006/09/01 18:03:19 umberto Exp $")
100
146
 
101
147
typedef enum {CLIP_LEFT, CLIP_MIDDLE, CLIP_RIGHT} CLIP_STATE;
102
148
 
105
151
#define SWAP( a, b, t) ( (t) = (a), (a) = (b), (b) = (t) )
106
152
#define EDGE_CHECK( x0, x, x1) ((x) < MS_MIN( (x0), (x1)) ? CLIP_LEFT : ((x) > MS_MAX( (x0), (x1)) ? CLIP_RIGHT : CLIP_MIDDLE ))
107
153
 
 
154
#ifndef INFINITY
108
155
#define INFINITY        (1.0e+30)
 
156
#endif
109
157
#define NEARZERO        (1.0e-30)       /* 1/INFINITY */
110
158
 
111
159
void msPrintShape(shapeObj *p) 
158
206
  shape->values = NULL;
159
207
  shape->numvalues = 0;
160
208
 
161
 
#ifdef USE_GEOS
162
209
  shape->geometry = NULL;
163
 
#endif
164
210
 
165
211
  /* annotation component */
166
212
  shape->text = NULL;
198
244
    to->numvalues = from->numvalues;
199
245
  }
200
246
 
201
 
  /* TODO add GEOS copy, or at least initialize to->geometry to NULL */
 
247
  to->geometry = NULL; /* GEOS code will build automatically if necessary */
202
248
 
203
249
  return(0);
204
250
}
223
269
  msInitShape(shape); /* now reset */
224
270
}
225
271
 
 
272
void msFreeLabelPathObj(labelPathObj *path)
 
273
{
 
274
  msFreeShape(&(path->bounds));
 
275
  msFree(path->path.point);
 
276
  msFree(path->angles);
 
277
  msFree(path);
 
278
}
 
279
 
226
280
void msShapeDeleteLine( shapeObj *shape, int line )
227
281
 
228
282
{
263
317
}
264
318
 
265
319
/* checks to see if ring r is an outer ring of shape */
266
 
static int isOuterRing(shapeObj *shape, int r)
 
320
static int isOuterRing(shapeObj *shape, int r) 
267
321
{
268
 
  int i, status=MS_TRUE;
 
322
  int i, status=MS_TRUE; 
269
323
 
270
324
  if(shape->numlines == 1) return(MS_TRUE);
271
325
 
733
787
}
734
788
 
735
789
/*
 
790
** offsets a point relative to an image position
 
791
*/
 
792
void msOffsetPointRelativeTo(pointObj *point, layerObj *layer)
 
793
{
 
794
  double x=0, y=0;
 
795
 
 
796
  if(layer->transform == MS_TRUE) return; /* nothing to do */
 
797
 
 
798
  if(layer->units == MS_PERCENTAGES) {
 
799
    point->x *= (layer->map->width-1);
 
800
    point->y *= (layer->map->height-1);
 
801
  }
 
802
 
 
803
  if(layer->transform == MS_FALSE || layer->transform == MS_UL) return; /* done */
 
804
 
 
805
  switch(layer->transform) {
 
806
  case MS_UC:
 
807
    x = (layer->map->width-1)/2;
 
808
    y = 0;
 
809
    break;
 
810
  case MS_UR:
 
811
    x = layer->map->width-1;
 
812
    y = 0;
 
813
    break;
 
814
  case MS_CL:
 
815
    x = 0;
 
816
    y = layer->map->height/2;
 
817
    break;
 
818
  case MS_CC:
 
819
    x = layer->map->width/2;
 
820
    y = layer->map->height/2;
 
821
    break;
 
822
  case MS_CR:
 
823
    x = layer->map->width-1;
 
824
    y = layer->map->height/2;
 
825
    break;
 
826
  case MS_LL:
 
827
    x = 0;
 
828
    y = layer->map->height-1;
 
829
    break;
 
830
  case MS_LC:
 
831
    x = layer->map->width/2;
 
832
    y = layer->map->height-1;
 
833
    break;
 
834
  case MS_LR:
 
835
    x = layer->map->width-1;
 
836
    y = layer->map->height-1;
 
837
    break;
 
838
  }
 
839
 
 
840
  point->x += x;
 
841
  point->y += y;
 
842
 
 
843
  return;
 
844
}
 
845
 
 
846
/*
 
847
** offsets a shape relative to an image position
 
848
*/
 
849
void msOffsetShapeRelativeTo(shapeObj *shape, layerObj *layer) 
 
850
{
 
851
  int i, j;
 
852
  double x=0, y=0;
 
853
 
 
854
  if(layer->transform == MS_TRUE) return; /* nothing to do */
 
855
 
 
856
  if(layer->units == MS_PERCENTAGES) {
 
857
    for (i=0; i<shape->numlines; i++) {
 
858
      for (j=0; j<shape->line[i].numpoints; j++) {
 
859
        shape->line[i].point[j].x *= (layer->map->width-1);
 
860
        shape->line[i].point[j].y *= (layer->map->height-1);
 
861
      }
 
862
    }
 
863
  }
 
864
 
 
865
  if(layer->transform == MS_FALSE || layer->transform == MS_UL) return; /* done */
 
866
 
 
867
  switch(layer->transform) {
 
868
  case MS_UC:
 
869
    x = (layer->map->width-1)/2;
 
870
    y = 0;
 
871
    break;
 
872
  case MS_UR:
 
873
    x = layer->map->width-1;
 
874
    y = 0;
 
875
    break;
 
876
  case MS_CL:
 
877
    x = 0;
 
878
    y = layer->map->height/2;
 
879
    break;
 
880
  case MS_CC:
 
881
    x = layer->map->width/2;
 
882
    y = layer->map->height/2;
 
883
    break;
 
884
  case MS_CR:
 
885
    x = layer->map->width-1;
 
886
    y = layer->map->height/2;
 
887
    break;
 
888
  case MS_LL:
 
889
    x = 0;
 
890
    y = layer->map->height-1;
 
891
    break;
 
892
  case MS_LC:
 
893
    x = layer->map->width/2;
 
894
    y = layer->map->height-1;
 
895
    break;
 
896
  case MS_LR:
 
897
    x = layer->map->width-1;
 
898
    y = layer->map->height-1;
 
899
    break;
 
900
  }
 
901
 
 
902
  for (i=0; i<shape->numlines; i++) {
 
903
    for (j=0; j<shape->line[i].numpoints; j++) {
 
904
      shape->line[i].point[j].x += x;
 
905
      shape->line[i].point[j].y += y;
 
906
    }
 
907
  }
 
908
 
 
909
  return;
 
910
}
 
911
 
 
912
/*
736
913
** converts from map coordinates to image coordinates
737
914
*/
738
915
void msTransformShapeToPixel(shapeObj *shape, rectObj extent, double cellsize)
1147
1324
  return(MS_SUCCESS);
1148
1325
}
1149
1326
 
 
1327
/*
 
1328
 * Calculate a series of label points for each character in the label for a
 
1329
 * given polyline.  The resultant series of points is stored in *labelpath.
 
1330
 * Note that the points and bounds are allocated in this function.  The
 
1331
 * polyline must be converted to image coordinates before calling this
 
1332
 * function.
 
1333
 */
 
1334
labelPathObj* msPolylineLabelPath(shapeObj *p, int min_length, fontSetObj *fontset, char *string, labelObj *label, double scalefactor, int *status)
 
1335
{
 
1336
  double line_length, max_line_length, segment_length, total_length, distance_along_segment;
 
1337
  double fwd_line_length, rev_line_length, text_length, text_start_length;
 
1338
  int segment_index, line_index;
 
1339
  
 
1340
  int i,j,k, inc, final_j;
 
1341
  double direction;
 
1342
  rectObj bbox;
 
1343
  lineObj bounds;
 
1344
  double *offsets;
 
1345
  double size, t;
 
1346
  double cx, cy; /* centre of a character, x & y values. */
 
1347
  
 
1348
  double theta;
 
1349
  double dx, dy, w, cos_t, sin_t;
 
1350
 
 
1351
  double **segment_lengths = NULL;
 
1352
  labelPathObj *labelpath = NULL;
 
1353
  char *font = NULL;
 
1354
 
 
1355
  /* Line smoothing kernel */
 
1356
  double kernel[] = {0.1,0.2,2,0.2,0.1}; /*{1.5, 2, 15, 2, 1.5};*/
 
1357
  double kernel_normal = 2.6; /* Must be sum of kernel elements */
 
1358
 
 
1359
  double letterspacing = 1.25;
 
1360
 
 
1361
  offsets = NULL;
 
1362
  
 
1363
  /* Assume success */
 
1364
  *status = MS_SUCCESS;
 
1365
 
 
1366
#ifndef GD_HAS_FTEX_XSHOW
 
1367
  goto FAILURE; /* we don't have a current enough version of GD, fall back to ANGLE AUTO */
 
1368
#else
 
1369
  /* Skip the label and use the normal algorithm if it has fewer than 2 characters */
 
1370
  if ( strlen(string) < 2 ) {
 
1371
    goto FAILURE;
 
1372
  }
 
1373
  
 
1374
  segment_index = line_index = 0;
 
1375
  total_length = max_line_length = 0.0;
 
1376
  
 
1377
  /* Determine longest line */
 
1378
  segment_lengths = (double**)malloc(sizeof(double*) * p->numlines);
 
1379
  for ( i = 0; i < p->numlines; i++ ) {
 
1380
    
 
1381
    segment_lengths[i] = (double*)malloc(sizeof(double) * p->line[i].numpoints);    
 
1382
    line_length = 0;
 
1383
    
 
1384
    for ( j = 1; j < p->line[i].numpoints; j++ ) {
 
1385
      segment_length = sqrt( pow((p->line[i].point[j].x - p->line[i].point[j-1].x), 2.0) +
 
1386
                             pow((p->line[i].point[j].y - p->line[i].point[j-1].y), 2.0) );
 
1387
      line_length += segment_length;
 
1388
      segment_lengths[i][j-1] = segment_length;
 
1389
      
 
1390
    }
 
1391
 
 
1392
    total_length += line_length;
 
1393
    
 
1394
    if ( line_length > max_line_length ) {
 
1395
      line_index = i;
 
1396
      max_line_length = line_length;
 
1397
    }
 
1398
  }
 
1399
 
 
1400
  i = line_index;
 
1401
  
 
1402
  if ( ((min_length != -1) && (total_length < min_length)) ) {
 
1403
    /* Too short */ 
 
1404
    *status = MS_FAILURE;
 
1405
    goto FAILURE;
 
1406
  }
 
1407
 
 
1408
  if ( p->line[i].numpoints < 2 ) {
 
1409
    /* Degenerate */
 
1410
    *status = MS_FAILURE;
 
1411
    goto FAILURE;
 
1412
  }
 
1413
 
 
1414
  if ( p->line[i].numpoints == 2 ) {
 
1415
    /* We can just use the regular algorithm to save some cycles */
 
1416
    goto FAILURE;
 
1417
  }
 
1418
  
 
1419
  /* Determine the total length of the text */
 
1420
  if ( msGetLabelSizeEx(string, label, &bbox, fontset, scalefactor, MS_FALSE, &offsets) == MS_FAILURE ) {
 
1421
    *status = MS_FAILURE;
 
1422
    goto FAILURE;
 
1423
  }
 
1424
 
 
1425
  size = label->size*scalefactor;
 
1426
  size = MS_MAX(size, label->minsize);
 
1427
  size = MS_MIN(size, label->maxsize);
 
1428
 
 
1429
  font = msLookupHashTable(&(fontset->fonts), label->font);
 
1430
  if(!font) {
 
1431
    if(label->font) 
 
1432
      msSetError(MS_TTFERR, "Requested font (%s) not found.", "msPolylineLabelPath()", label->font);
 
1433
    else
 
1434
      msSetError(MS_TTFERR, "Requested font (NULL) not found.", "msPolylineLabelPath()");
 
1435
    *status = MS_FAILURE;
 
1436
    goto FAILURE;
 
1437
  }
 
1438
  
 
1439
  text_length = letterspacing * (bbox.maxx - bbox.minx);
 
1440
 
 
1441
  /* If the text length is way longer than the line, skip adding the
 
1442
     label if it isn't forced (long extrapolated labels tend to be
 
1443
     ugly) */
 
1444
  if ( text_length > 1.5 * max_line_length && label->force == MS_FALSE ) {
 
1445
    *status = MS_FAILURE;
 
1446
    goto FAILURE;
 
1447
  }
 
1448
  
 
1449
  /* Allocate the labelpath */
 
1450
  labelpath = (labelPathObj*)malloc(sizeof(labelPathObj));
 
1451
  labelpath->path.numpoints = strlen(string);
 
1452
  labelpath->path.point = (pointObj*)calloc(labelpath->path.numpoints,sizeof(pointObj));
 
1453
  labelpath->angles = (double*)malloc(sizeof(double) * (labelpath->path.numpoints));
 
1454
  msInitShape(&(labelpath->bounds));
 
1455
 
 
1456
  /* The bounds will have two points for each character plus an endpoint:
 
1457
     the UL corners of each bbox will be tied together and the LL corners
 
1458
     will be tied together. */
 
1459
  bounds.numpoints = 2*strlen(string) + 1;
 
1460
  bounds.point = (pointObj*)malloc(sizeof(pointObj) * bounds.numpoints);
 
1461
                                   
 
1462
  /* The points start at (max_line_length - text_length) / 2 in order to be centred */
 
1463
  text_start_length = (max_line_length - text_length) / 2.0;
 
1464
  
 
1465
  /* The text is longer than the line: extrapolate the first and last segments */
 
1466
  if ( text_start_length < 0.0 ) {
 
1467
    
 
1468
    j = 0;
 
1469
    final_j = p->line[i].numpoints - 1;
 
1470
    fwd_line_length = rev_line_length = 0;
 
1471
    
 
1472
  } else {
 
1473
 
 
1474
    /* Proceed until we've traversed text_start_length in distance */
 
1475
    fwd_line_length = 0;
 
1476
    j = 0;
 
1477
    while ( fwd_line_length < text_start_length )
 
1478
      fwd_line_length += segment_lengths[i][j++];
 
1479
 
 
1480
    j--;
 
1481
 
 
1482
    /* Determine the last segment */ 
 
1483
    rev_line_length = 0;
 
1484
    final_j = p->line[i].numpoints - 1;
 
1485
    while ( rev_line_length < text_start_length ) {
 
1486
      rev_line_length += segment_lengths[i][final_j - 1];
 
1487
      final_j--;
 
1488
    }
 
1489
    final_j++;
 
1490
 
 
1491
  }
 
1492
 
 
1493
  if ( final_j == 0 )
 
1494
    final_j = 1;
 
1495
  
 
1496
  /* Determine if the line is mostly left to right or right to left */
 
1497
  direction = 0;
 
1498
  k = j;
 
1499
  while ( k < final_j ) {
 
1500
    direction += p->line[i].point[k+1].x - p->line[i].point[k].x;
 
1501
    k++;
 
1502
  }
 
1503
  
 
1504
  if ( direction > 0 ) {
 
1505
 
 
1506
    /* j is already correct */
 
1507
    inc = 1;
 
1508
 
 
1509
    /* Length of the segment containing the starting point */
 
1510
    segment_length = segment_lengths[i][j];
 
1511
    /* Determine how far along the segment we need to go */
 
1512
    t = 1 - (fwd_line_length - text_start_length) / segment_length;
 
1513
    
 
1514
  } else {
 
1515
 
 
1516
    j = final_j;
 
1517
    inc = -1;
 
1518
 
 
1519
    /* Length of the segment containing the starting point */
 
1520
    segment_length = segment_lengths[i][j-1];
 
1521
    t = 1 - (rev_line_length - text_start_length) / segment_length;
 
1522
    
 
1523
  }
 
1524
    
 
1525
  distance_along_segment = t * segment_length; /* Starting point */
 
1526
  
 
1527
  theta = 0;
 
1528
  k = 0;
 
1529
  w = 0;
 
1530
  while ( k < labelpath->path.numpoints ) {
 
1531
    int m;
 
1532
    double x,y;
 
1533
      
 
1534
    x = t * (p->line[i].point[j+inc].x - p->line[i].point[j].x) + p->line[i].point[j].x;
 
1535
    y = t * (p->line[i].point[j+inc].y - p->line[i].point[j].y) + p->line[i].point[j].y;
 
1536
 
 
1537
    /* Average this label point with its neighbors according to the
 
1538
       smoothing kernel */
 
1539
    
 
1540
    if ( k == 0 ) {
 
1541
      labelpath->path.point[k].x += (kernel[0] + kernel[1]) * x;      
 
1542
      labelpath->path.point[k].y += (kernel[0] + kernel[1]) * y;      
 
1543
      
 
1544
    } else if ( k == 1 ) {
 
1545
      labelpath->path.point[k].x += kernel[0] * x;
 
1546
      labelpath->path.point[k].y += kernel[0] * y;
 
1547
      
 
1548
    } else if ( k == labelpath->path.numpoints - 2 ) {
 
1549
      labelpath->path.point[k].x += kernel[4] * x;
 
1550
      labelpath->path.point[k].y += kernel[4] * y;
 
1551
      
 
1552
    } else if ( k == labelpath->path.numpoints - 1 ) {
 
1553
      labelpath->path.point[k].x += (kernel[3] + kernel[4]) * x;
 
1554
      labelpath->path.point[k].y += (kernel[3] + kernel[4]) * y;
 
1555
      }
 
1556
      
 
1557
    for (m = 0; m < 5; m++) {
 
1558
      if ( m + k - 2 < 0 || m + k - 2 > labelpath->path.numpoints - 1 )
 
1559
        continue;
 
1560
      
 
1561
      labelpath->path.point[k+m-2].x += kernel[m]*x;
 
1562
      labelpath->path.point[k+m-2].y += kernel[m]*y;
 
1563
    }
 
1564
    
 
1565
    w = letterspacing*offsets[k];
 
1566
    
 
1567
    /* Add the character's width to the distance along the line */
 
1568
    distance_along_segment += w;
 
1569
 
 
1570
    /* If we still have segments left and we've past the current
 
1571
       segment, move to the next one */
 
1572
    
 
1573
    if ( inc == 1 && j < p->line[i].numpoints - 2 ) {
 
1574
      
 
1575
      while ( j < p->line[i].numpoints - 2 && distance_along_segment > segment_lengths[i][j] ) {
 
1576
        distance_along_segment -= segment_lengths[i][j];
 
1577
        
 
1578
        /* Move to next segment */
 
1579
        j += inc;
 
1580
      }
 
1581
 
 
1582
      segment_length = segment_lengths[i][j];
 
1583
      
 
1584
      
 
1585
    } else if ( inc == -1 && j > 1 ) {
 
1586
 
 
1587
      while ( j > 1 && distance_along_segment > segment_lengths[i][j-1] ) {
 
1588
        distance_along_segment -= segment_lengths[i][j-1];
 
1589
        
 
1590
        /* Move to next segment */
 
1591
        j += inc;
 
1592
      }
 
1593
      
 
1594
      segment_length = segment_lengths[i][j-1];
 
1595
      
 
1596
    }
 
1597
    
 
1598
    /* Recalculate interpolation parameter */
 
1599
    t = distance_along_segment / segment_length;
 
1600
    
 
1601
    k++;
 
1602
    
 
1603
  }
 
1604
  
 
1605
  /* Pre-calc the character's centre y value.  Used for rotation adjustment.  */
 
1606
  cy = -size / 2.0;
 
1607
    
 
1608
  labelpath->path.point[0].x /= kernel_normal;
 
1609
  labelpath->path.point[0].y /= kernel_normal;
 
1610
  
 
1611
  /* Average the points and calculate each angle */
 
1612
  for (k = 1; k <= labelpath->path.numpoints; k++) {
 
1613
 
 
1614
    if ( k < labelpath->path.numpoints ) {  
 
1615
      labelpath->path.point[k].x /= kernel_normal;
 
1616
      labelpath->path.point[k].y /= kernel_normal;
 
1617
      dx = labelpath->path.point[k].x - labelpath->path.point[k-1].x;
 
1618
      dy = labelpath->path.point[k].y - labelpath->path.point[k-1].y;
 
1619
    } else {
 
1620
      /* Handle the last character */
 
1621
      dx = t * (p->line[i].point[j+inc].x - p->line[i].point[j].x) + p->line[i].point[j].x - labelpath->path.point[k-1].x;
 
1622
      dy = t * (p->line[i].point[j+inc].y - p->line[i].point[j].y) + p->line[i].point[j].y - labelpath->path.point[k-1].y;
 
1623
    }
 
1624
 
 
1625
    theta = -atan2(dy,dx);
 
1626
 
 
1627
    /* If the difference between subsequent angles is > 80% of 180deg
 
1628
       bail because the line likely overlaps itself. */
 
1629
    if ( k > 2 && abs(theta - labelpath->angles[k-2]) > 0.4 * MS_PI ) {
 
1630
      *status = MS_FAILURE;
 
1631
      goto FAILURE;
 
1632
    }
 
1633
      
 
1634
    /* msDebug("s: %c (x,y): (%0.2f,%0.2f) t: %0.2f\n", string[k-1], labelpath->path.point[k-1].x, labelpath->path.point[k-1].y, theta); */
 
1635
 
 
1636
    labelpath->angles[k-1] = theta;
 
1637
  
 
1638
    /* Move the previous point so that when the character is rotated and
 
1639
       placed it is centred on the line */
 
1640
    cos_t = cos(theta);
 
1641
    sin_t = sin(theta);
 
1642
  
 
1643
    w = letterspacing*offsets[k-1];
 
1644
 
 
1645
    cx = 0; /* Center the character vertically only */
 
1646
 
 
1647
    dx = - (cx * cos_t + cy * sin_t);
 
1648
    dy = - (cy * cos_t - cx * sin_t);
 
1649
  
 
1650
    labelpath->path.point[k-1].x += dx;
 
1651
    labelpath->path.point[k-1].y += dy;
 
1652
 
 
1653
    /* Calculate the bounds */
 
1654
    bbox.minx = 0;
 
1655
    bbox.maxx = w;
 
1656
    bbox.maxy = 0;
 
1657
    bbox.miny = -size;
 
1658
 
 
1659
    /* Add the label buffer to the bounds */
 
1660
    bbox.maxx += label->buffer;
 
1661
    bbox.maxy += label->buffer;
 
1662
    bbox.minx -= label->buffer;
 
1663
    bbox.miny -= label->buffer;
 
1664
  
 
1665
    if ( k < labelpath->path.numpoints ) {
 
1666
      /* Transform the bbox too.  We take the UL and LL corners and rotate
 
1667
         then translate them. */
 
1668
      bounds.point[k-1].x = (bbox.minx * cos_t + bbox.maxy * sin_t) + labelpath->path.point[k-1].x;
 
1669
      bounds.point[k-1].y = (bbox.maxy * cos_t - bbox.minx * sin_t) + labelpath->path.point[k-1].y;
 
1670
 
 
1671
      /* Start at end and work towards the half way point */
 
1672
      bounds.point[bounds.numpoints - k - 1].x = (bbox.minx * cos_t + bbox.miny * sin_t) + labelpath->path.point[k-1].x;
 
1673
      bounds.point[bounds.numpoints - k - 1].y = (bbox.miny * cos_t - bbox.minx * sin_t) + labelpath->path.point[k-1].y;
 
1674
 
 
1675
    } else {
 
1676
    
 
1677
      /* This is the last character in the string so we take the UR and LR
 
1678
         corners of the bbox */
 
1679
      bounds.point[k-1].x = (bbox.maxx * cos_t + bbox.maxy * sin_t) + labelpath->path.point[k-1].x;
 
1680
      bounds.point[k-1].y = (bbox.maxy * cos_t - bbox.maxx * sin_t) + labelpath->path.point[k-1].y;
 
1681
  
 
1682
      bounds.point[bounds.numpoints - k - 1].x = (bbox.maxx * cos_t + bbox.miny * sin_t) + labelpath->path.point[k-1].x;
 
1683
      bounds.point[bounds.numpoints - k - 1].y = (bbox.miny * cos_t - bbox.maxx * sin_t) + labelpath->path.point[k-1].y;
 
1684
    }
 
1685
 
 
1686
  }
 
1687
 
 
1688
  /* Close the bounds */
 
1689
  bounds.point[bounds.numpoints - 1].x = bounds.point[0].x;
 
1690
  bounds.point[bounds.numpoints - 1].y = bounds.point[0].y;
 
1691
  
 
1692
  /* Convert the bounds to a shape and store them in the labelpath */
 
1693
  if ( msAddLineDirectly(&(labelpath->bounds), &bounds) == MS_FAILURE ) {
 
1694
    *status = MS_FAILURE;
 
1695
    goto FAILURE;
 
1696
  }
 
1697
  
 
1698
  msComputeBounds(&(labelpath->bounds));
 
1699
 
 
1700
  if ( segment_lengths ) {
 
1701
    for ( i = 0; i < p->numlines; i++ )
 
1702
      free(segment_lengths[i]);
 
1703
    free(segment_lengths);
 
1704
  }
 
1705
  
 
1706
  free(offsets);
 
1707
  
 
1708
  return labelpath;
 
1709
#endif
 
1710
 
 
1711
FAILURE:
 
1712
  if ( segment_lengths ) {
 
1713
    for ( i = 0; i < p->numlines; i++ )
 
1714
      free(segment_lengths[i]);
 
1715
    free(segment_lengths);
 
1716
  }
 
1717
    
 
1718
  if ( offsets )
 
1719
    free(offsets);
 
1720
  
 
1721
  if ( labelpath ) {
 
1722
    msFreeLabelPathObj(labelpath);
 
1723
    labelpath = NULL;
 
1724
  }
 
1725
    
 
1726
  return NULL;
 
1727
}
 
1728
 
1150
1729
/* ===========================================================================
1151
1730
   Pretty printing of primitive objects
1152
1731
   ======================================================================== */