Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/maputfgrid.cpp
Line
Count
Source
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  UTFGrid rendering functions (using AGG)
6
 * Author:   Francois Desjarlais
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1996-2007 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
#include "maputfgrid.h"
32
#include "mapagg.h"
33
#include "renderers/agg/include/agg_rasterizer_scanline_aa.h"
34
#include "renderers/agg/include/agg_basics.h"
35
#include "renderers/agg/include/agg_renderer_scanline.h"
36
#include "renderers/agg/include/agg_scanline_bin.h"
37
#include "renderers/agg/include/agg_gamma_functions.h"
38
#include "renderers/agg/include/agg_conv_stroke.h"
39
#include "renderers/agg/include/agg_ellipse.h"
40
41
#include <memory>
42
#include <vector>
43
44
typedef mapserver::int32u band_type;
45
typedef mapserver::row_ptr_cache<band_type> rendering_buffer;
46
typedef pixfmt_utf<utfpix32, rendering_buffer> pixfmt_utf32;
47
typedef mapserver::renderer_base<pixfmt_utf32> renderer_base;
48
typedef mapserver::rasterizer_scanline_aa<> rasterizer_scanline;
49
typedef mapserver::renderer_scanline_bin_solid<renderer_base> renderer_scanline;
50
51
static const utfpix32 UTF_WATER = utfpix32(32);
52
53
0
#define utfitem(c) utfpix32(c)
54
55
namespace {
56
57
struct shapeData {
58
  std::string datavalues{};
59
  std::string itemvalue{};
60
  band_type utfvalue = 0;
61
  int serialid = 0;
62
};
63
64
/*
65
 * UTFGrid specific polygon adaptor.
66
 */
67
class polygon_adaptor_utf final : public polygon_adaptor {
68
public:
69
  polygon_adaptor_utf(shapeObj *shape, int utfres_in)
70
0
      : polygon_adaptor(shape), utfresolution(utfres_in) {}
71
72
0
  unsigned vertex(double *x, double *y) override {
73
0
    if (m_point < m_pend) {
74
0
      bool first = m_point == m_line->point;
75
0
      *x = m_point->x / utfresolution;
76
0
      *y = m_point->y / utfresolution;
77
0
      m_point++;
78
0
      return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to;
79
0
    }
80
0
    *x = *y = 0.0;
81
0
    if (!m_stop) {
82
83
0
      m_line++;
84
0
      if (m_line >= m_lend) {
85
0
        m_stop = true;
86
0
        return mapserver::path_cmd_end_poly;
87
0
      }
88
89
0
      m_point = m_line->point;
90
0
      m_pend = &(m_line->point[m_line->numpoints]);
91
0
      return mapserver::path_cmd_end_poly;
92
0
    }
93
0
    return mapserver::path_cmd_stop;
94
0
  }
95
96
private:
97
  int utfresolution;
98
};
99
100
/*
101
 * UTFGrid specific line adaptor.
102
 */
103
class line_adaptor_utf final : public line_adaptor {
104
public:
105
  line_adaptor_utf(shapeObj *shape, int utfres_in)
106
0
      : line_adaptor(shape), utfresolution(utfres_in) {}
107
108
0
  unsigned vertex(double *x, double *y) override {
109
0
    if (m_point < m_pend) {
110
0
      bool first = m_point == m_line->point;
111
0
      *x = m_point->x / utfresolution;
112
0
      *y = m_point->y / utfresolution;
113
0
      m_point++;
114
0
      return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to;
115
0
    }
116
0
    m_line++;
117
0
    *x = *y = 0.0;
118
0
    if (m_line >= m_lend)
119
0
      return mapserver::path_cmd_stop;
120
121
0
    m_point = m_line->point;
122
0
    m_pend = &(m_line->point[m_line->numpoints]);
123
124
0
    return vertex(x, y);
125
0
  }
126
127
private:
128
  int utfresolution;
129
};
130
131
class UTFGridRenderer {
132
public:
133
  std::vector<shapeData> table{};
134
  int utfresolution = 0;
135
  int layerwatch = 0;
136
  bool renderlayer = false;
137
  bool useutfitem = false;
138
  bool useutfdata = false;
139
  bool duplicates = false;
140
  band_type utfvalue = 0;
141
  layerObj *utflayer = nullptr;
142
  int width = 0;
143
  int height = 0;
144
  std::vector<band_type> buffer{};
145
  rendering_buffer m_rendering_buffer{};
146
  pixfmt_utf32 m_pixel_format{};
147
  renderer_base m_renderer_base{};
148
  rasterizer_scanline m_rasterizer{};
149
  renderer_scanline m_renderer_scanline{};
150
  mapserver::scanline_bin sl_utf{};
151
  std::unique_ptr<mapserver::conv_stroke<line_adaptor_utf>> stroke{};
152
};
153
154
} // namespace
155
156
#define UTFGRID_RENDERER(image)                                                \
157
0
  (static_cast<UTFGridRenderer *>((image)->img.plugin))
158
159
/*
160
 * Encode to avoid unavailable char in the JSON
161
 */
162
0
static unsigned int encodeForRendering(unsigned int toencode) {
163
0
  unsigned int encoded;
164
0
  encoded = toencode + 32;
165
  /* 34 => " */
166
0
  if (encoded >= 34) {
167
0
    encoded = encoded + 1;
168
0
  }
169
  /* 92 => \ */
170
0
  if (encoded >= 92) {
171
0
    encoded = encoded + 1;
172
0
  }
173
0
  return encoded;
174
0
}
175
176
/*
177
 * Decode value to have the initial one
178
 */
179
0
static unsigned int decodeRendered(unsigned int todecode) {
180
0
  unsigned int decoded;
181
182
0
  if (todecode >= 92)
183
0
    todecode--;
184
185
0
  if (todecode >= 34)
186
0
    todecode--;
187
188
0
  decoded = todecode - 32;
189
190
0
  return decoded;
191
0
}
192
193
/*
194
 * Add the shapeObj UTFDATA and UTFITEM to the lookup table.
195
 */
196
0
static band_type addToTable(UTFGridRenderer *r, shapeObj *p) {
197
  /* Looks for duplicates. */
198
0
  if (r->duplicates == false && r->useutfitem) {
199
0
    const auto itemvalue = p->values[r->utflayer->utfitemindex];
200
0
    for (const auto &tableItem : r->table) {
201
0
      if (tableItem.itemvalue == itemvalue) {
202
        /* Found a copy of the values in the table. */
203
0
        return tableItem.utfvalue;
204
0
      }
205
0
    }
206
0
  }
207
208
  /* Data added to the table */
209
0
  shapeData table;
210
0
  char *escaped = msEvalTextExpressionJSonEscape(&r->utflayer->utfdata, p);
211
0
  table.datavalues = escaped ? escaped : "";
212
0
  msFree(escaped);
213
214
  /* If UTFITEM is set in the mapfile we add its value to the table */
215
0
  if (r->useutfitem)
216
0
    table.itemvalue = p->values[r->utflayer->utfitemindex];
217
218
0
  table.serialid = static_cast<int>(r->table.size() + 1);
219
220
  /* Simple operation so we don't have unavailable char in the JSON */
221
0
  const auto utfvalue = encodeForRendering(table.serialid);
222
0
  table.utfvalue = utfvalue;
223
224
0
  r->table.emplace_back(std::move(table));
225
226
0
  return utfvalue;
227
0
}
228
229
/*
230
 * Use AGG to render any path.
231
 */
232
template <class vertex_source>
233
0
static int utfgridRenderPath(imageObj *img, vertex_source &path) {
234
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
235
0
  r->m_rasterizer.reset();
236
0
  r->m_rasterizer.filling_rule(mapserver::fill_even_odd);
237
0
  r->m_rasterizer.add_path(path);
238
0
  r->m_renderer_scanline.color(utfitem(r->utfvalue));
239
0
  mapserver::render_scanlines(r->m_rasterizer, r->sl_utf,
240
0
                              r->m_renderer_scanline);
241
0
  return MS_SUCCESS;
242
0
}
Unexecuted instantiation: maputfgrid.cpp:int utfgridRenderPath<(anonymous namespace)::polygon_adaptor_utf>(imageObj*, (anonymous namespace)::polygon_adaptor_utf&)
Unexecuted instantiation: maputfgrid.cpp:int utfgridRenderPath<mapserver::path_base<mapserver::vertex_block_storage<double, 8u, 256u> > >(imageObj*, mapserver::path_base<mapserver::vertex_block_storage<double, 8u, 256u> >&)
Unexecuted instantiation: maputfgrid.cpp:int utfgridRenderPath<mapserver::conv_stroke<(anonymous namespace)::line_adaptor_utf, mapserver::null_markers> >(imageObj*, mapserver::conv_stroke<(anonymous namespace)::line_adaptor_utf, mapserver::null_markers>&)
243
244
/*
245
 * Initialize the renderer, create buffer, allocate memory.
246
 */
247
static imageObj *utfgridCreateImage(int width, int height,
248
                                    outputFormatObj *format,
249
0
                                    colorObj * /*bg*/) {
250
0
  auto r = std::unique_ptr<UTFGridRenderer>(new UTFGridRenderer);
251
252
0
  r->utfresolution =
253
0
      atof(msGetOutputFormatOption(format, "UTFRESOLUTION", "4"));
254
0
  if (r->utfresolution < 1) {
255
0
    msSetError(MS_MISCERR, "UTFRESOLUTION smaller that 1 in the mapfile.",
256
0
               "utfgridCreateImage()");
257
0
    return nullptr;
258
0
  }
259
0
  r->duplicates =
260
0
      EQUAL("true", msGetOutputFormatOption(format, "DUPLICATES", "true"));
261
262
0
  r->width = width / r->utfresolution;
263
0
  r->height = height / r->utfresolution;
264
265
0
  r->buffer.resize(static_cast<size_t>(r->width) * r->height);
266
267
  /* AGG specific operations */
268
0
  r->m_rendering_buffer.attach(&r->buffer[0], r->width, r->height, r->width);
269
0
  r->m_pixel_format.attach(r->m_rendering_buffer);
270
0
  r->m_renderer_base.attach(r->m_pixel_format);
271
0
  r->m_renderer_scanline.attach(r->m_renderer_base);
272
0
  r->m_renderer_base.clear(UTF_WATER);
273
0
  r->m_rasterizer.gamma(mapserver::gamma_none());
274
275
0
  imageObj *image = (imageObj *)msSmallCalloc(1, sizeof(imageObj));
276
0
  image->img.plugin = r.release();
277
278
0
  return image;
279
0
}
280
281
/*
282
 * Free all the memory used by the renderer.
283
 */
284
0
static int utfgridFreeImage(imageObj *img) {
285
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
286
0
  delete r;
287
288
0
  img->img.plugin = NULL;
289
290
0
  return MS_SUCCESS;
291
0
}
292
293
/*
294
 * Update a character in the utfgrid.
295
 */
296
static int utfgridUpdateChar(imageObj *img, band_type oldChar,
297
0
                             band_type newChar) {
298
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
299
300
0
  for (auto &ch : r->buffer) {
301
0
    if (ch == oldChar) {
302
0
      ch = newChar;
303
0
    }
304
0
  }
305
306
0
  return MS_SUCCESS;
307
0
}
308
309
/*
310
 * Remove unnecessary data that didn't made it to the final grid.
311
 */
312
0
static int utfgridCleanData(imageObj *img) {
313
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
314
315
0
  std::vector<bool> usedChar;
316
0
  usedChar.resize(r->table.size());
317
318
0
  int itemFound = 0;
319
320
0
  for (const auto ch : r->buffer) {
321
0
    const auto rendered = decodeRendered(ch);
322
0
    if (rendered != 0 && !usedChar[rendered - 1]) {
323
0
      itemFound++;
324
0
      usedChar[rendered - 1] = true;
325
0
    }
326
0
  }
327
328
0
  std::vector<shapeData> updatedData;
329
0
  updatedData.reserve(itemFound);
330
331
0
  for (const auto &tableItem : r->table) {
332
0
    if (usedChar[decodeRendered(tableItem.utfvalue) - 1]) {
333
0
      updatedData.emplace_back(tableItem);
334
0
      auto &newData = updatedData.back();
335
336
0
      newData.serialid = static_cast<int>(updatedData.size());
337
338
0
      const band_type utfvalue = encodeForRendering(newData.serialid);
339
340
0
      utfgridUpdateChar(img, newData.utfvalue, utfvalue);
341
0
      newData.utfvalue = utfvalue;
342
0
    }
343
0
  }
344
345
0
  r->table = std::move(updatedData);
346
347
0
  return MS_SUCCESS;
348
0
}
349
350
/*
351
 * Print the renderer data as JSON.
352
 */
353
static int utfgridSaveImage(imageObj *img, mapObj * /*map*/, FILE *fp,
354
0
                            outputFormatObj * /*format*/) {
355
0
  utfgridCleanData(img);
356
357
0
  const UTFGridRenderer *renderer = UTFGRID_RENDERER(img);
358
359
0
  if (renderer->layerwatch > 1)
360
0
    return MS_FAILURE;
361
362
0
  const int imgheight = renderer->height;
363
0
  const int imgwidth = renderer->width;
364
365
0
  msIO_fprintf(fp, "{\"grid\":[");
366
367
  /* Print the buffer */
368
0
  std::vector<wchar_t> string;
369
0
  string.resize(imgwidth + 1);
370
0
  for (int row = 0; row < imgheight; row++) {
371
372
    /* Need a comma between each line but JSON must not start with a comma. */
373
0
    if (row != 0)
374
0
      msIO_fprintf(fp, ",");
375
0
    msIO_fprintf(fp, "\"");
376
0
    for (int col = 0; col < imgwidth; col++) {
377
      /* Get the data from buffer. */
378
0
      band_type pixelid = renderer->buffer[(row * imgwidth) + col];
379
0
      string[col] = pixelid;
380
0
    }
381
382
    /* Conversion to UTF-8 encoding */
383
#if defined(_WIN32) && !defined(__CYGWIN__)
384
    const char *encoding = "UCS-2LE";
385
#else
386
0
    const char *encoding = "UCS-4LE";
387
0
#endif
388
389
0
    char *utf8 = msConvertWideStringToUTF8(string.data(), encoding);
390
0
    msIO_fprintf(fp, "%s", utf8);
391
0
    msFree(utf8);
392
0
    msIO_fprintf(fp, "\"");
393
0
  }
394
395
0
  msIO_fprintf(fp, "],\"keys\":[\"\"");
396
397
  /* Print the specified key */
398
0
  for (const auto &table : renderer->table) {
399
0
    msIO_fprintf(fp, ",");
400
401
0
    if (renderer->useutfitem) {
402
0
      char *pszEscaped = msEscapeJSonString(table.itemvalue.c_str());
403
0
      msIO_fprintf(fp, "\"%s\"", pszEscaped);
404
0
      msFree(pszEscaped);
405
0
    }
406
    /* If no UTFITEM specified use the serial ID as the key */
407
0
    else
408
0
      msIO_fprintf(fp, "\"%i\"", table.serialid);
409
0
  }
410
411
0
  msIO_fprintf(fp, "],\"data\":{");
412
413
  /* Print the data */
414
0
  if (renderer->useutfdata) {
415
0
    bool first = true;
416
0
    for (const auto &table : renderer->table) {
417
0
      if (!first)
418
0
        msIO_fprintf(fp, ",");
419
0
      first = false;
420
421
0
      if (renderer->useutfitem) {
422
0
        char *pszEscaped = msEscapeJSonString(table.itemvalue.c_str());
423
0
        msIO_fprintf(fp, "\"%s\":", pszEscaped);
424
0
        msFree(pszEscaped);
425
0
      }
426
      /* If no UTFITEM specified use the serial ID as the key */
427
0
      else
428
0
        msIO_fprintf(fp, "\"%i\":", table.serialid);
429
430
0
      msIO_fprintf(fp, "%s", table.datavalues.c_str());
431
0
    }
432
0
  }
433
0
  msIO_fprintf(fp, "}}");
434
435
0
  return MS_SUCCESS;
436
0
}
437
438
/*
439
 * Starts a layer for UTFGrid renderer.
440
 */
441
0
static int utfgridStartLayer(imageObj *img, mapObj * /*map*/, layerObj *layer) {
442
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
443
444
  /* Look if the layer uses the UTFGrid output format */
445
0
  if (layer->utfdata.string != 0) {
446
0
    r->useutfdata = true;
447
0
  }
448
449
  /* layerwatch is set to 1 on first layer treated. Doesn't allow multiple
450
   * layers. */
451
0
  if (!r->layerwatch) {
452
0
    r->layerwatch++;
453
454
0
    r->renderlayer = true;
455
0
    r->utflayer = layer;
456
0
    layer->refcount++;
457
458
    /* Verify if renderer needs to use UTFITEM */
459
0
    if (r->utflayer->utfitem)
460
0
      r->useutfitem = true;
461
0
  }
462
  /* If multiple layers, send error */
463
0
  else {
464
0
    r->layerwatch++;
465
0
    msSetError(MS_MISCERR,
466
0
               "MapServer does not support multiple UTFGrid layers rendering "
467
0
               "simultaneously.",
468
0
               "utfgridStartLayer()");
469
0
    return MS_FAILURE;
470
0
  }
471
472
0
  return MS_SUCCESS;
473
0
}
474
475
/*
476
 * Tell renderer the layer is done.
477
 */
478
0
static int utfgridEndLayer(imageObj *img, mapObj * /*map*/, layerObj *layer) {
479
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
480
481
  /* Look if the layer was rendered, if it was then turn off rendering. */
482
0
  if (r->renderlayer) {
483
0
    r->utflayer = NULL;
484
0
    layer->refcount--;
485
0
    r->renderlayer = false;
486
0
  }
487
488
0
  return MS_SUCCESS;
489
0
}
490
491
/*
492
 * Do the table operations on the shapes. Allow multiple types of data to be
493
 * rendered.
494
 */
495
0
static int utfgridStartShape(imageObj *img, shapeObj *shape) {
496
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
497
498
0
  if (!r->renderlayer)
499
0
    return MS_FAILURE;
500
501
  /* Table operations */
502
0
  r->utfvalue = addToTable(r, shape);
503
504
0
  return MS_SUCCESS;
505
0
}
506
507
/*
508
 * Tells the renderer that the shape's rendering is done.
509
 */
510
0
static int utfgridEndShape(imageObj *img, shapeObj *) {
511
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
512
513
0
  r->utfvalue = 0;
514
0
  return MS_SUCCESS;
515
0
}
516
517
/*
518
 * Function that renders polygons into UTFGrid.
519
 */
520
static int utfgridRenderPolygon(imageObj *img, shapeObj *polygonshape,
521
0
                                colorObj *) {
522
0
  const UTFGridRenderer *r = UTFGRID_RENDERER(img);
523
524
  /* utfvalue is set to 0 if the shape isn't in the table. */
525
0
  if (r->utfvalue == 0) {
526
0
    return MS_FAILURE;
527
0
  }
528
529
  /* Render the polygon */
530
0
  polygon_adaptor_utf polygons(polygonshape, r->utfresolution);
531
0
  utfgridRenderPath(img, polygons);
532
533
0
  return MS_SUCCESS;
534
0
}
535
536
/*
537
 * Function that renders lines into UTFGrid. Starts by looking if the line is a
538
 * polygon outline, draw it if it's not.
539
 */
540
static int utfgridRenderLine(imageObj *img, shapeObj *lineshape,
541
0
                             strokeStyleObj *linestyle) {
542
0
  UTFGridRenderer *r = UTFGRID_RENDERER(img);
543
544
  /* utfvalue is set to 0 if the shape isn't in the table. */
545
0
  if (r->utfvalue == 0) {
546
0
    return MS_SUCCESS;
547
    /* If we don't get a character to draw we just skip execution
548
     * instead of failing
549
     */
550
0
  }
551
552
  /* Render the line */
553
0
  line_adaptor_utf lines(lineshape, r->utfresolution);
554
555
0
  if (!r->stroke) {
556
0
    r->stroke.reset(new mapserver::conv_stroke<line_adaptor_utf>(lines));
557
0
  } else {
558
0
    r->stroke->attach(lines);
559
0
  }
560
0
  r->stroke->width(linestyle->width / r->utfresolution);
561
0
  utfgridRenderPath(img, *r->stroke);
562
563
0
  return MS_SUCCESS;
564
0
}
565
566
/*
567
 * Function that render vector type symbols into UTFGrid.
568
 */
569
static int utfgridRenderVectorSymbol(imageObj *img, double x, double y,
570
0
                                     symbolObj *symbol, symbolStyleObj *style) {
571
0
  const UTFGridRenderer *r = UTFGRID_RENDERER(img);
572
0
  double ox = symbol->sizex * 0.5;
573
0
  double oy = symbol->sizey * 0.5;
574
575
  /* utfvalue is set to 0 if the shape isn't in the table. */
576
0
  if (r->utfvalue == 0) {
577
0
    return MS_FAILURE;
578
0
  }
579
580
  /* Pathing the symbol */
581
0
  mapserver::path_storage path = imageVectorSymbol(symbol);
582
583
  /* Transformation to the right size/scale. */
584
0
  mapserver::trans_affine mtx;
585
0
  mtx *= mapserver::trans_affine_translation(-ox, -oy);
586
0
  mtx *= mapserver::trans_affine_scaling(style->scale / r->utfresolution);
587
0
  mtx *= mapserver::trans_affine_rotation(-style->rotation);
588
0
  mtx *= mapserver::trans_affine_translation(x / r->utfresolution,
589
0
                                             y / r->utfresolution);
590
0
  path.transform(mtx);
591
592
  /* Rendering the symbol. */
593
0
  utfgridRenderPath(img, path);
594
595
0
  return MS_SUCCESS;
596
0
}
597
598
/*
599
 * Function that renders Pixmap type symbols into UTFGrid.
600
 */
601
static int utfgridRenderPixmapSymbol(imageObj *img, double x, double y,
602
0
                                     symbolObj *symbol, symbolStyleObj *style) {
603
0
  const UTFGridRenderer *r = UTFGRID_RENDERER(img);
604
0
  rasterBufferObj *pixmap = symbol->pixmap_buffer;
605
606
  /* utfvalue is set to 0 if the shape isn't in the table. */
607
0
  if (r->utfvalue == 0) {
608
0
    return MS_FAILURE;
609
0
  }
610
611
  /* Pathing the symbol BBox */
612
0
  mapserver::path_storage pixmap_bbox;
613
0
  double w, h;
614
0
  w = pixmap->width * style->scale / (2.0);
615
0
  h = pixmap->height * style->scale / (2.0);
616
0
  pixmap_bbox.move_to((x - w) / r->utfresolution, (y - h) / r->utfresolution);
617
0
  pixmap_bbox.line_to((x + w) / r->utfresolution, (y - h) / r->utfresolution);
618
0
  pixmap_bbox.line_to((x + w) / r->utfresolution, (y + h) / r->utfresolution);
619
0
  pixmap_bbox.line_to((x - w) / r->utfresolution, (y + h) / r->utfresolution);
620
621
  /* Rendering the symbol */
622
0
  utfgridRenderPath(img, pixmap_bbox);
623
624
0
  return MS_SUCCESS;
625
0
}
626
627
/*
628
 * Function that render ellipse type symbols into UTFGrid.
629
 */
630
static int utfgridRenderEllipseSymbol(imageObj *img, double x, double y,
631
                                      symbolObj *symbol,
632
0
                                      symbolStyleObj *style) {
633
0
  const UTFGridRenderer *r = UTFGRID_RENDERER(img);
634
635
  /* utfvalue is set to 0 if the shape isn't in the table. */
636
0
  if (r->utfvalue == 0) {
637
0
    return MS_FAILURE;
638
0
  }
639
640
  /* Pathing the symbol. */
641
0
  mapserver::path_storage path;
642
0
  mapserver::ellipse ellipse(
643
0
      x / r->utfresolution, y / r->utfresolution,
644
0
      symbol->sizex * style->scale / 2 / r->utfresolution,
645
0
      symbol->sizey * style->scale / 2 / r->utfresolution);
646
0
  path.concat_path(ellipse);
647
648
  /* Rotation if necessary. */
649
0
  if (style->rotation != 0) {
650
0
    mapserver::trans_affine mtx;
651
0
    mtx *= mapserver::trans_affine_translation(-x / r->utfresolution,
652
0
                                               -y / r->utfresolution);
653
0
    mtx *= mapserver::trans_affine_rotation(-style->rotation);
654
0
    mtx *= mapserver::trans_affine_translation(x / r->utfresolution,
655
0
                                               y / r->utfresolution);
656
0
    path.transform(mtx);
657
0
  }
658
659
  /* Rendering the symbol. */
660
0
  utfgridRenderPath(img, path);
661
662
0
  return MS_SUCCESS;
663
0
}
664
665
static int utfgridRenderGlyphs(imageObj *img, const textSymbolObj *ts,
666
                               colorObj * /*c*/, colorObj * /*oc*/, int /*ow*/,
667
0
                               int isMarker) {
668
669
0
  const textPathObj *tp = ts->textpath;
670
0
  const UTFGridRenderer *r = UTFGRID_RENDERER(img);
671
672
  /* If it's not a marker then it's a label or other thing and we don't
673
   *  want to draw it on the map
674
   */
675
0
  if (!isMarker) {
676
0
    return MS_SUCCESS; // Stop the rendering with no errors
677
0
  }
678
679
  /* utfvalue is set to 0 if the shape isn't in the table. */
680
0
  if (r->utfvalue == 0) {
681
0
    return MS_SUCCESS; // Stop the rendering with no errors
682
0
  }
683
684
  /* Pathing the symbol BBox */
685
0
  mapserver::path_storage box;
686
0
  double size, x, y;
687
688
0
  size = tp->glyph_size;
689
0
  ;
690
0
  x = tp->glyphs->pnt.x;
691
0
  y = tp->glyphs->pnt.y;
692
693
0
  box.move_to((x) / r->utfresolution, (y) / r->utfresolution);
694
0
  box.line_to((x + size) / r->utfresolution, (y) / r->utfresolution);
695
0
  box.line_to((x + size) / r->utfresolution, (y - size) / r->utfresolution);
696
0
  box.line_to((x) / r->utfresolution, (y - size) / r->utfresolution);
697
698
  /* Rotation if necessary. */
699
0
  if (tp->glyphs->rot != 0) {
700
0
    mapserver::trans_affine mtx;
701
0
    mtx *= mapserver::trans_affine_translation(-x / r->utfresolution,
702
0
                                               -y / r->utfresolution);
703
0
    mtx *= mapserver::trans_affine_rotation(-tp->glyphs->rot);
704
0
    mtx *= mapserver::trans_affine_translation(x / r->utfresolution,
705
0
                                               y / r->utfresolution);
706
0
    box.transform(mtx);
707
0
  }
708
709
  /* Rendering the symbol */
710
0
  utfgridRenderPath(img, box);
711
712
0
  return MS_SUCCESS;
713
0
}
714
715
0
static int utfgridFreeSymbol(symbolObj *) { return MS_SUCCESS; }
716
717
/*
718
 * Add the necessary functions for UTFGrid to the renderer VTable.
719
 */
720
0
int msPopulateRendererVTableUTFGrid(rendererVTableObj *renderer) {
721
0
  renderer->default_transform_mode = MS_TRANSFORM_SIMPLIFY;
722
723
0
  renderer->createImage = &utfgridCreateImage;
724
0
  renderer->freeImage = &utfgridFreeImage;
725
0
  renderer->saveImage = &utfgridSaveImage;
726
727
0
  renderer->startLayer = &utfgridStartLayer;
728
0
  renderer->endLayer = &utfgridEndLayer;
729
730
0
  renderer->startShape = &utfgridStartShape;
731
0
  renderer->endShape = &utfgridEndShape;
732
733
0
  renderer->renderPolygon = &utfgridRenderPolygon;
734
0
  renderer->renderGlyphs = &utfgridRenderGlyphs;
735
0
  renderer->renderLine = &utfgridRenderLine;
736
0
  renderer->renderVectorSymbol = &utfgridRenderVectorSymbol;
737
0
  renderer->renderPixmapSymbol = &utfgridRenderPixmapSymbol;
738
0
  renderer->renderEllipseSymbol = &utfgridRenderEllipseSymbol;
739
740
0
  renderer->freeSymbol = &utfgridFreeSymbol;
741
742
0
  renderer->loadImageFromFile = msLoadMSRasterBufferFromFile;
743
744
0
  return MS_SUCCESS;
745
0
}