Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapscale.c
Line
Count
Source
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Scale object rendering.
6
 * Author:   Steve Lime and the MapServer team.
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29
30
#include "mapserver.h"
31
32
0
#define VMARGIN 3 /* buffer around the scalebar */
33
0
#define HMARGIN 3
34
#define VSPACING .8 /* spacing (% of font height) between scalebar and text */
35
0
#define VSLOP 5     /* makes things fit a bit better vertically */
36
37
/*
38
** Match this with with unit enumerations is mapserver.h
39
*/
40
static char *unitText[9] = {
41
    "in", "ft", "mi", "m", "km",
42
    "dd", "??", "??", "NM"}; /* MS_PIXEL and MS_PERCENTAGE not used */
43
double inchesPerUnit[9] = {1,       12, 63360.0, 39.3701,   39370.1,
44
                           4374754, 1,  1,       72913.3858};
45
46
0
static double roundInterval(double d) {
47
0
  if (d < .001)
48
0
    return (MS_NINT(d * 10000) / 10000.0);
49
0
  if (d < .01)
50
0
    return (MS_NINT(d * 1000) / 1000.0);
51
0
  if (d < .1)
52
0
    return (MS_NINT(d * 100) / 100.0);
53
0
  if (d < 1)
54
0
    return (MS_NINT(d * 10) / 10.0);
55
0
  if (d < 100)
56
0
    return (MS_NINT(d));
57
0
  if (d < 1000)
58
0
    return (MS_NINT(d / 10) * 10);
59
0
  if (d < 10000)
60
0
    return (MS_NINT(d / 100) * 100);
61
0
  if (d < 100000)
62
0
    return (MS_NINT(d / 1000) * 1000);
63
0
  if (d < 1000000)
64
0
    return (MS_NINT(d / 10000) * 10000);
65
0
  if (d < 10000000)
66
0
    return (MS_NINT(d / 100000) * 100000);
67
0
  if (d < 100000000)
68
0
    return (MS_NINT(d / 1000000) * 1000000);
69
70
0
  return (-1);
71
0
}
72
73
/*
74
** Calculate the approximate scale based on a few parameters. Note that this
75
*assumes the scale is
76
** the same in the x direction as in the y direction, so run msAdjustExtent(...)
77
*first.
78
*/
79
int msCalculateScale(rectObj extent, int units, int width, int height,
80
0
                     double resolution, double *scale) {
81
0
  double md, gd, center_y;
82
83
  /* if((extent.maxx == extent.minx) || (extent.maxy == extent.miny))   */
84
0
  if (!MS_VALID_EXTENT(extent)) {
85
0
    msSetError(MS_MISCERR,
86
0
               "Invalid image extent, minx=%lf, miny=%lf, maxx=%lf, maxy=%lf.",
87
0
               "msCalculateScale()", extent.minx, extent.miny, extent.maxx,
88
0
               extent.maxy);
89
0
    return (MS_FAILURE);
90
0
  }
91
92
0
  if ((width <= 0) || (height <= 0)) {
93
0
    msSetError(MS_MISCERR, "Invalid image width or height.",
94
0
               "msCalculateScale()");
95
0
    return (MS_FAILURE);
96
0
  }
97
98
0
  switch (units) {
99
0
  case (MS_DD):
100
0
  case (MS_METERS):
101
0
  case (MS_KILOMETERS):
102
0
  case (MS_MILES):
103
0
  case (MS_NAUTICALMILES):
104
0
  case (MS_INCHES):
105
0
  case (MS_FEET):
106
0
    center_y = (extent.miny + extent.maxy) / 2.0;
107
0
    md = (width - 1) /
108
0
         (resolution *
109
0
          msInchesPerUnit(
110
0
              units, center_y)); /* remember, we use a pixel-center to
111
                                    pixel-center extent, hence the width-1 */
112
0
    gd = extent.maxx - extent.minx;
113
0
    *scale = gd / md;
114
0
    break;
115
0
  default:
116
0
    *scale = -1; /* this is not an error */
117
0
    break;
118
0
  }
119
120
0
  return (MS_SUCCESS);
121
0
}
122
123
0
double msInchesPerUnit(int units, double center_lat) {
124
0
  (void)center_lat;
125
0
  double lat_adj = 1.0, ipu = 1.0;
126
127
0
  switch (units) {
128
0
  case (MS_METERS):
129
0
  case (MS_KILOMETERS):
130
0
  case (MS_MILES):
131
0
  case (MS_NAUTICALMILES):
132
0
  case (MS_INCHES):
133
0
  case (MS_FEET):
134
0
    ipu = inchesPerUnit[units];
135
0
    break;
136
0
  case (MS_DD):
137
    /* With geographical (DD) coordinates, we adjust the inchesPerUnit
138
     * based on the latitude of the center of the view. For this we assume
139
     * we have a perfect sphere and just use cos(lat) in our calculation.
140
     */
141
#ifdef ENABLE_VARIABLE_INCHES_PER_DEGREE
142
    if (center_lat != 0.0) {
143
      double cos_lat;
144
      cos_lat = cos(MS_PI * center_lat / 180.0);
145
      lat_adj = sqrt(1 + cos_lat * cos_lat) / sqrt(2.0);
146
    }
147
#endif
148
0
    ipu = inchesPerUnit[units] * lat_adj;
149
0
    break;
150
0
  default:
151
0
    break;
152
0
  }
153
154
0
  return ipu;
155
0
}
156
157
0
#define X_STEP_SIZE 5
158
159
0
imageObj *msDrawScalebar(mapObj *map) {
160
0
  int status;
161
0
  char label[32];
162
0
  double i, msx;
163
0
  int j;
164
0
  int isx, sx, sy, ox, oy, state, dsx;
165
0
  pointObj p;
166
0
  rectObj r;
167
0
  imageObj *image = NULL;
168
0
  double fontWidth, fontHeight;
169
0
  outputFormatObj *format = NULL;
170
0
  strokeStyleObj strokeStyle = {0};
171
0
  shapeObj shape;
172
0
  lineObj line;
173
0
  pointObj points[5];
174
0
  textSymbolObj ts;
175
0
  rendererVTableObj *renderer;
176
177
0
  strokeStyle.patternlength = 0;
178
0
  initTextSymbol(&ts);
179
180
0
  if ((int)map->units == -1) {
181
0
    msSetError(MS_MISCERR, "Map units not set.", "msDrawScalebar()");
182
0
    return (NULL);
183
0
  }
184
185
0
  renderer = MS_MAP_RENDERER(map);
186
0
  if (!renderer || !MS_MAP_RENDERER(map)->supports_pixel_buffer) {
187
0
    msSetError(MS_MISCERR, "Outputformat not supported for scalebar",
188
0
               "msDrawScalebar()");
189
0
    return (NULL);
190
0
  }
191
192
0
  msPopulateTextSymbolForLabelAndString(
193
0
      &ts, &map->scalebar.label, msStrdup("0123456789"), 1.0,
194
0
      map->resolution / map->defresolution, 0);
195
196
  /*
197
   *  A string containing the ten decimal digits is rendered to compute an
198
   * average cell size for each number, which is used later to place labels on
199
   * the scalebar.
200
   */
201
202
0
  if (msGetTextSymbolSize(map, &ts, &r) != MS_SUCCESS) {
203
0
    return NULL;
204
0
  }
205
0
  fontWidth = (r.maxx - r.minx) / 10.0;
206
0
  fontHeight = r.maxy - r.miny;
207
208
0
  map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height);
209
0
  status = msCalculateScale(map->extent, map->units, map->width, map->height,
210
0
                            map->resolution, &map->scaledenom);
211
0
  if (status != MS_SUCCESS) {
212
0
    return (NULL);
213
0
  }
214
0
  dsx = map->scalebar.width - 2 * HMARGIN;
215
0
  do {
216
0
    msx = (map->cellsize * dsx) / (msInchesPerUnit(map->scalebar.units, 0) /
217
0
                                   msInchesPerUnit(map->units, 0));
218
0
    i = roundInterval(msx / map->scalebar.intervals);
219
0
    snprintf(label, sizeof(label), "%g",
220
0
             map->scalebar.intervals * i); /* last label */
221
0
    isx = MS_NINT((i / (msInchesPerUnit(map->units, 0) /
222
0
                        msInchesPerUnit(map->scalebar.units, 0))) /
223
0
                  map->cellsize);
224
0
    sx = (map->scalebar.intervals * isx) +
225
0
         MS_NINT((1.5 + strlen(label) / 2.0 +
226
0
                  strlen(unitText[map->scalebar.units])) *
227
0
                 fontWidth);
228
229
0
    if (sx <= (map->scalebar.width - 2 * HMARGIN))
230
0
      break; /* it will fit */
231
232
0
    dsx -= X_STEP_SIZE; /* change the desired size in hopes that it will fit in
233
                           user supplied width */
234
0
  } while (1);
235
236
0
  sy = (2 * VMARGIN) + MS_NINT(VSPACING * fontHeight) + fontHeight +
237
0
       map->scalebar.height - VSLOP;
238
239
  /*Ensure we have an image format representing the options for the scalebar.*/
240
0
  msApplyOutputFormat(&format, map->outputformat, map->scalebar.transparent);
241
242
0
  if (map->scalebar.transparent == MS_OFF) {
243
0
    if (!MS_VALID_COLOR(map->scalebar.imagecolor))
244
0
      MS_INIT_COLOR(map->scalebar.imagecolor, 255, 255, 255, 255);
245
0
  }
246
0
  image = msImageCreate(map->scalebar.width, sy, format, map->web.imagepath,
247
0
                        map->web.imageurl, map->resolution, map->defresolution,
248
0
                        &map->scalebar.imagecolor);
249
250
  /* did we succeed in creating the image? */
251
0
  if (!image) {
252
0
    msSetError(MS_MISCERR, "Unable to initialize image.", "msDrawScalebar()");
253
0
    return NULL;
254
0
  }
255
0
  image->map = map;
256
257
  /* drop this reference to output format */
258
0
  msApplyOutputFormat(&format, NULL, MS_NOOVERRIDE);
259
260
0
  switch (map->scalebar.align) {
261
0
  case (MS_ALIGN_LEFT):
262
0
    ox = HMARGIN;
263
0
    break;
264
0
  case (MS_ALIGN_RIGHT):
265
0
    ox = MS_NINT((map->scalebar.width - sx) + fontWidth);
266
0
    break;
267
0
  default:
268
0
    ox = MS_NINT((map->scalebar.width - sx) / 2.0 +
269
0
                 fontWidth / 2.0); /* center the computed scalebar */
270
0
  }
271
0
  oy = VMARGIN;
272
273
0
  switch (map->scalebar.style) {
274
0
  case (0): {
275
276
0
    line.numpoints = 5;
277
0
    line.point = points;
278
0
    shape.line = &line;
279
0
    shape.numlines = 1;
280
0
    if (MS_VALID_COLOR(map->scalebar.color)) {
281
0
      INIT_STROKE_STYLE(strokeStyle);
282
0
      strokeStyle.color = &map->scalebar.outlinecolor;
283
0
      strokeStyle.color->alpha = 255;
284
0
      strokeStyle.width = 1;
285
0
    }
286
0
    map->scalebar.backgroundcolor.alpha = 255;
287
0
    map->scalebar.color.alpha = 255;
288
0
    state = 1; /* 1 means filled */
289
0
    for (j = 0; j < map->scalebar.intervals; j++) {
290
0
      points[0].x = points[4].x = points[3].x = ox + j * isx + 0.5;
291
0
      points[0].y = points[4].y = points[1].y = oy + 0.5;
292
0
      points[1].x = points[2].x = ox + (j + 1) * isx + 0.5;
293
0
      points[2].y = points[3].y = oy + map->scalebar.height + 0.5;
294
0
      if (state == 1 && MS_VALID_COLOR(map->scalebar.color))
295
0
        status = renderer->renderPolygon(image, &shape, &map->scalebar.color);
296
0
      else if (MS_VALID_COLOR(map->scalebar.backgroundcolor))
297
0
        status = renderer->renderPolygon(image, &shape,
298
0
                                         &map->scalebar.backgroundcolor);
299
300
0
      if (MS_UNLIKELY(status == MS_FAILURE)) {
301
0
        goto scale_cleanup;
302
0
      }
303
304
0
      if (strokeStyle.color) {
305
0
        status = renderer->renderLine(image, &shape, &strokeStyle);
306
307
0
        if (MS_UNLIKELY(status == MS_FAILURE)) {
308
0
          goto scale_cleanup;
309
0
        }
310
0
      }
311
312
0
      snprintf(label, sizeof(label), "%g", j * i);
313
0
      map->scalebar.label.position = MS_CC;
314
0
      p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
315
0
      p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
316
0
      status = msDrawLabel(map, image, p, msStrdup(label), &map->scalebar.label,
317
0
                           1.0);
318
0
      if (MS_UNLIKELY(status == MS_FAILURE)) {
319
0
        goto scale_cleanup;
320
0
      }
321
0
      state = -state;
322
0
    }
323
0
    snprintf(label, sizeof(label), "%g", j * i);
324
0
    ox = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
325
0
    snprintf(label, sizeof(label), "%g %s", j * i,
326
0
             unitText[map->scalebar.units]);
327
0
    map->scalebar.label.position = MS_CR;
328
0
    p.x = ox; /* + MS_NINT(fontPtr->w/2); */
329
0
    p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
330
0
    status =
331
0
        msDrawLabel(map, image, p, msStrdup(label), &map->scalebar.label, 1.0);
332
0
    if (MS_UNLIKELY(status == MS_FAILURE)) {
333
0
      goto scale_cleanup;
334
0
    }
335
0
    break;
336
0
  }
337
0
  case (1): {
338
0
    line.numpoints = 2;
339
0
    line.point = points;
340
0
    shape.line = &line;
341
0
    shape.numlines = 1;
342
0
    if (MS_VALID_COLOR(map->scalebar.color)) {
343
0
      strokeStyle.width = 1;
344
0
      strokeStyle.color = &map->scalebar.color;
345
0
    }
346
347
0
    points[0].y = points[1].y = oy;
348
0
    points[0].x = ox;
349
0
    points[1].x = ox + isx * map->scalebar.intervals;
350
0
    status = renderer->renderLine(image, &shape, &strokeStyle);
351
0
    if (MS_UNLIKELY(status == MS_FAILURE)) {
352
0
      goto scale_cleanup;
353
0
    }
354
355
0
    points[0].y = oy;
356
0
    points[1].y = oy + map->scalebar.height;
357
0
    p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
358
0
    for (j = 0; j <= map->scalebar.intervals; j++) {
359
0
      points[0].x = points[1].x = ox + j * isx;
360
0
      status = renderer->renderLine(image, &shape, &strokeStyle);
361
0
      if (MS_UNLIKELY(status == MS_FAILURE)) {
362
0
        goto scale_cleanup;
363
0
      }
364
365
0
      snprintf(label, sizeof(label), "%g", j * i);
366
0
      if (j != map->scalebar.intervals) {
367
0
        map->scalebar.label.position = MS_CC;
368
0
        p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
369
0
      } else {
370
0
        snprintf(label, sizeof(label), "%g %s", j * i,
371
0
                 unitText[map->scalebar.units]);
372
0
        map->scalebar.label.position = MS_CR;
373
0
        p.x = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
374
0
      }
375
0
      status = msDrawLabel(map, image, p, msStrdup(label), &map->scalebar.label,
376
0
                           1.0);
377
0
      if (MS_UNLIKELY(status == MS_FAILURE)) {
378
0
        goto scale_cleanup;
379
0
      }
380
0
    }
381
0
    break;
382
0
  }
383
0
  default:
384
0
    msSetError(MS_MISCERR, "Unsupported scalebar style.", "msDrawScalebar()");
385
0
    return (NULL);
386
0
  }
387
388
0
scale_cleanup:
389
0
  freeTextSymbol(&ts);
390
0
  if (MS_UNLIKELY(status == MS_FAILURE)) {
391
0
    msFreeImage(image);
392
0
    return NULL;
393
0
  }
394
0
  return (image);
395
0
}
396
397
0
int msEmbedScalebar(mapObj *map, imageObj *img) {
398
0
  int l, index, s, status = MS_SUCCESS;
399
0
  pointObj point;
400
0
  imageObj *image = NULL;
401
0
  rendererVTableObj *renderer;
402
0
  symbolObj *embeddedSymbol;
403
0
  char *imageType = NULL;
404
405
0
  index = msGetSymbolIndex(&(map->symbolset), "scalebar", MS_FALSE);
406
0
  if (index != -1)
407
0
    msRemoveSymbol(&(map->symbolset),
408
0
                   index); /* remove cached symbol in case the function is
409
   called multiple times with different zoom levels */
410
411
0
  if ((embeddedSymbol = msGrowSymbolSet(&map->symbolset)) == NULL)
412
0
    return MS_FAILURE;
413
414
0
  s = map->symbolset.numsymbols;
415
0
  map->symbolset.numsymbols++;
416
417
0
  if (!MS_RENDERER_PLUGIN(map->outputformat) ||
418
0
      !MS_MAP_RENDERER(map)->supports_pixel_buffer) {
419
0
    imageType = msStrdup(map->imagetype); /* save format */
420
0
    if MS_DRIVER_CAIRO (map->outputformat)
421
0
      map->outputformat = msSelectOutputFormat(map, "cairopng");
422
0
    else
423
0
      map->outputformat = msSelectOutputFormat(map, "png");
424
425
0
    msInitializeRendererVTable(map->outputformat);
426
0
  }
427
0
  renderer = MS_MAP_RENDERER(map);
428
429
0
  image = msDrawScalebar(map);
430
431
0
  if (imageType) {
432
0
    map->outputformat =
433
0
        msSelectOutputFormat(map, imageType); /* restore format */
434
0
    msFree(imageType);
435
0
  }
436
437
0
  if (!image) {
438
0
    return MS_FAILURE;
439
0
  }
440
0
  embeddedSymbol->pixmap_buffer = calloc(1, sizeof(rasterBufferObj));
441
0
  MS_CHECK_ALLOC(embeddedSymbol->pixmap_buffer, sizeof(rasterBufferObj),
442
0
                 MS_FAILURE);
443
444
0
  if (MS_SUCCESS !=
445
0
      renderer->getRasterBufferCopy(image, embeddedSymbol->pixmap_buffer)) {
446
0
    return MS_FAILURE;
447
0
  }
448
449
0
  embeddedSymbol->type = MS_SYMBOL_PIXMAP; /* initialize a few things */
450
0
  embeddedSymbol->name = msStrdup("scalebar");
451
0
  embeddedSymbol->sizex = embeddedSymbol->pixmap_buffer->width;
452
0
  embeddedSymbol->sizey = embeddedSymbol->pixmap_buffer->height;
453
0
  if (map->scalebar.transparent) {
454
0
    embeddedSymbol->transparent = MS_TRUE;
455
0
    embeddedSymbol->transparentcolor = 0;
456
0
  }
457
458
0
  switch (map->scalebar.position) {
459
0
  case (MS_LL):
460
0
    point.x = MS_NINT(embeddedSymbol->pixmap_buffer->width / 2.0) +
461
0
              map->scalebar.offsetx;
462
0
    point.y = map->height -
463
0
              MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) -
464
0
              map->scalebar.offsety;
465
0
    break;
466
0
  case (MS_LR):
467
0
    point.x = map->width - MS_NINT(embeddedSymbol->pixmap_buffer->width / 2.0) -
468
0
              map->scalebar.offsetx;
469
0
    point.y = map->height -
470
0
              MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) -
471
0
              map->scalebar.offsety;
472
0
    break;
473
0
  case (MS_LC):
474
0
    point.x = MS_NINT(map->width / 2.0) + map->scalebar.offsetx;
475
0
    point.y = map->height -
476
0
              MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) -
477
0
              map->scalebar.offsety;
478
0
    break;
479
0
  case (MS_UR):
480
0
    point.x = map->width - MS_NINT(embeddedSymbol->pixmap_buffer->width / 2.0) -
481
0
              map->scalebar.offsetx;
482
0
    point.y = MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) +
483
0
              map->scalebar.offsety;
484
0
    break;
485
0
  case (MS_UL):
486
0
    point.x = MS_NINT(embeddedSymbol->pixmap_buffer->width / 2.0) +
487
0
              map->scalebar.offsetx;
488
0
    point.y = MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) +
489
0
              map->scalebar.offsety;
490
0
    break;
491
0
  case (MS_UC):
492
0
    point.x = MS_NINT(map->width / 2.0) + map->scalebar.offsetx;
493
0
    point.y = MS_NINT(embeddedSymbol->pixmap_buffer->height / 2.0) +
494
0
              map->scalebar.offsety;
495
0
    break;
496
0
  }
497
498
0
  l = msGetLayerIndex(map, "__embed__scalebar");
499
0
  if (l == -1) {
500
0
    if (msGrowMapLayers(map) == NULL)
501
0
      return (-1);
502
0
    l = map->numlayers;
503
0
    map->numlayers++;
504
0
    if (initLayer((GET_LAYER(map, l)), map) == -1)
505
0
      return (-1);
506
0
    GET_LAYER(map, l)->name = msStrdup("__embed__scalebar");
507
0
    GET_LAYER(map, l)->type = MS_LAYER_POINT;
508
509
0
    if (msGrowLayerClasses(GET_LAYER(map, l)) == NULL)
510
0
      return (-1);
511
512
0
    if (initClass(GET_LAYER(map, l)->class[0]) == -1)
513
0
      return (-1);
514
0
    GET_LAYER(map, l)->numclasses = 1; /* so we make sure to free it */
515
516
    /* update the layer order list with the layer's index. */
517
0
    map->layerorder[l] = l;
518
0
  }
519
520
0
  GET_LAYER(map, l)->status = MS_ON;
521
0
  if (map->scalebar.postlabelcache) { /* add it directly to the image */
522
0
    if (msMaybeAllocateClassStyle(GET_LAYER(map, l)->class[0], 0) == MS_FAILURE)
523
0
      return MS_FAILURE;
524
0
    GET_LAYER(map, l)->class[0]->styles[0]->symbol = s;
525
0
    status = msDrawMarkerSymbol(map, img, &point,
526
0
                                GET_LAYER(map, l)->class[0] -> styles[0], 1.0);
527
0
    if (MS_UNLIKELY(status == MS_FAILURE)) {
528
0
      goto embed_cleanup;
529
0
    }
530
0
  } else {
531
0
    if (!GET_LAYER(map, l)->class[0] -> labels) {
532
0
      if (msGrowClassLabels(GET_LAYER(map, l)->class[0]) == NULL)
533
0
        return MS_FAILURE;
534
0
      initLabel(GET_LAYER(map, l)->class[0] -> labels[0]);
535
0
      GET_LAYER(map, l)->class[0]->numlabels = 1;
536
0
      GET_LAYER(map, l)->class[0]->labels[0]->force = MS_TRUE;
537
0
      GET_LAYER(map, l)->class[0]->labels[0]->size =
538
0
          MS_MEDIUM; /* must set a size to have a valid label definition */
539
0
      GET_LAYER(map, l)->class[0]->labels[0]->priority = MS_MAX_LABEL_PRIORITY;
540
0
    }
541
0
    if (GET_LAYER(map, l)->class[0] -> labels[0] -> numstyles == 0) {
542
0
      if (msGrowLabelStyles(GET_LAYER(map, l)->class[0] -> labels[0]) == NULL)
543
0
        return (MS_FAILURE);
544
0
      GET_LAYER(map, l)->class[0]->labels[0]->numstyles = 1;
545
0
      initStyle(GET_LAYER(map, l)->class[0] -> labels[0] -> styles[0]);
546
0
      GET_LAYER(map, l)->class[0]->labels[0]->styles[0]->_geomtransform.type =
547
0
          MS_GEOMTRANSFORM_LABELPOINT;
548
0
    }
549
0
    GET_LAYER(map, l)->class[0]->labels[0]->styles[0]->symbol = s;
550
0
    status = msAddLabel(map, img, GET_LAYER(map, l)->class[0] -> labels[0], l,
551
0
                        0, NULL, &point, -1, NULL);
552
0
    if (MS_UNLIKELY(status == MS_FAILURE)) {
553
0
      goto embed_cleanup;
554
0
    }
555
0
  }
556
557
0
embed_cleanup:
558
  /* Mark layer as deleted so that it doesn't interfere with html legends or
559
   * with saving maps */
560
0
  GET_LAYER(map, l)->status = MS_DELETE;
561
562
0
  msFreeImage(image);
563
0
  return status;
564
0
}
565
566
/************************************************************************/
567
/* These two functions are used in PHP/Mapscript and Swig/Mapscript     */
568
/************************************************************************/
569
570
/************************************************************************/
571
/*  double GetDeltaExtentsUsingScale(double scale, int units,           */
572
/*                                   double centerLat, int width,       */
573
/*                                   double resolution)                 */
574
/*                                                                      */
575
/*      Utility function to return the maximum extent using the         */
576
/*      scale and the width of the image.                               */
577
/*                                                                      */
578
/*      Base on the function msCalculateScale (mapscale.c)              */
579
/************************************************************************/
580
double GetDeltaExtentsUsingScale(double scale, int units, double centerLat,
581
0
                                 int width, double resolution) {
582
0
  double md = 0.0;
583
0
  double dfDelta = -1.0;
584
585
0
  if (scale <= 0 || width <= 0)
586
0
    return -1;
587
588
0
  switch (units) {
589
0
  case (MS_DD):
590
0
  case (MS_METERS):
591
0
  case (MS_KILOMETERS):
592
0
  case (MS_MILES):
593
0
  case (MS_NAUTICALMILES):
594
0
  case (MS_INCHES):
595
0
  case (MS_FEET):
596
    /* remember, we use a pixel-center to pixel-center extent, hence the width-1
597
     */
598
0
    md = (width - 1) / (resolution * msInchesPerUnit(units, centerLat));
599
0
    dfDelta = md * scale;
600
0
    break;
601
602
0
  default:
603
0
    break;
604
0
  }
605
606
0
  return dfDelta;
607
0
}
608
609
/************************************************************************/
610
/*    static double Pix2Georef(int nPixPos, int nPixMin, double nPixMax,*/
611
/*                              double dfGeoMin, double dfGeoMax,       */
612
/*                              bool bULisYOrig)                        */
613
/*                                                                      */
614
/*      Utility function to convert a pixel pos to georef pos. If       */
615
/*      bULisYOrig parameter is set to true then the upper left is      */
616
/*      considered to be the Y origin.                                  */
617
/*                                                                      */
618
/************************************************************************/
619
double Pix2Georef(int nPixPos, int nPixMin, int nPixMax, double dfGeoMin,
620
0
                  double dfGeoMax, int bULisYOrig) {
621
0
  double dfPosGeo = 0.0;
622
623
0
  const double dfWidthGeo = dfGeoMax - dfGeoMin;
624
0
  const int nWidthPix = nPixMax - nPixMin;
625
626
0
  if (dfWidthGeo > 0.0 && nWidthPix > 0) {
627
0
    const double dfPixToGeo = dfWidthGeo / (double)nWidthPix;
628
629
0
    int nDeltaPix;
630
0
    if (!bULisYOrig)
631
0
      nDeltaPix = nPixPos - nPixMin;
632
0
    else
633
0
      nDeltaPix = nPixMax - nPixPos;
634
635
0
    const double dfDeltaGeo = nDeltaPix * dfPixToGeo;
636
637
0
    dfPosGeo = dfGeoMin + dfDeltaGeo;
638
0
  }
639
0
  return (dfPosGeo);
640
0
}
641
642
/* This function converts a pixel value in geo ref. The return value is in
643
 * layer units. This function has been added for the purpose of the ticket #1340
644
 */
645
646
0
double Pix2LayerGeoref(mapObj *map, layerObj *layer, int value) {
647
0
  double cellsize =
648
0
      MS_MAX(MS_CELLSIZE(map->extent.minx, map->extent.maxx, map->width),
649
0
             MS_CELLSIZE(map->extent.miny, map->extent.maxy, map->height));
650
651
0
  double resolutionFactor = map->resolution / map->defresolution;
652
0
  double unitsFactor = 1;
653
654
0
  if (layer->sizeunits != MS_PIXELS)
655
0
    unitsFactor =
656
0
        msInchesPerUnit(map->units, 0) / msInchesPerUnit(layer->sizeunits, 0);
657
658
0
  return value * cellsize * resolutionFactor * unitsFactor;
659
0
}