Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapgraticule.c
Line
Count
Source
1
/**********************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Graticule Renderer
6
 * Author:   John Novak, Novacell Technologies (jnovak@novacell.com)
7
 *
8
 **********************************************************************
9
 * Copyright (c) 2003, John Novak, Novacell Technologies
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 OR
22
 * 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
 ****************************************************************************/
28
29
#include "mapserver.h"
30
#include <assert.h>
31
#include "mapproject.h"
32
33
/**********************************************************************************************************************
34
 *
35
 */
36
typedef enum { posBottom = 1, posTop, posLeft, posRight } msGraticulePosition;
37
38
typedef enum {
39
  lpDefault = 0,
40
  lpDDMMSS = 1,
41
  lpDDMM,
42
  lpDD
43
} msLabelProcessingType;
44
45
void DefineAxis(int iTickCountTarget, double *Min, double *Max, double *Inc);
46
static int _AdjustLabelPosition(layerObj *pLayer, shapeObj *pShape,
47
                                msGraticulePosition ePosition);
48
static void _FormatLabel(layerObj *pLayer, shapeObj *pShape,
49
                         double dDataToFormat);
50
51
int msGraticuleLayerInitItemInfo(layerObj *layer);
52
53
0
#define MAPGRATICULE_ARC_SUBDIVISION_DEFAULT (256)
54
0
#define MAPGRATICULE_ARC_MINIMUM (16)
55
0
#define MAPGRATICULE_FORMAT_STRING_DEFAULT "%5.2g"
56
0
#define MAPGRATICULE_FORMAT_STRING_DDMMSS "%3d %02d %02d"
57
0
#define MAPGRATICULE_FORMAT_STRING_DDMM "%3d %02d"
58
0
#define MAPGRATICULE_FORMAT_STRING_DD "%3d"
59
60
/**********************************************************************************************************************
61
 *
62
 */
63
0
int msGraticuleLayerOpen(layerObj *layer) {
64
0
  graticuleObj *pInfo = layer->grid;
65
66
0
  if (pInfo == NULL)
67
0
    return MS_FAILURE;
68
69
0
  pInfo->dincrementlatitude = 15.0;
70
0
  pInfo->dincrementlongitude = 15.0;
71
0
  pInfo->dwhichlatitude = -90.0;
72
0
  pInfo->dwhichlongitude = -180.0;
73
0
  pInfo->bvertical = 1;
74
75
0
  if (layer->numclasses == 0)
76
0
    msDebug("GRID layer has no classes, nothing will be rendered.\n");
77
78
0
  if (layer->numclasses > 0 && layer->class[0] -> numlabels > 0)
79
0
    pInfo->blabelaxes = 1;
80
0
  else
81
0
    pInfo->blabelaxes = 0;
82
83
0
  if (pInfo->labelformat == NULL) {
84
0
    pInfo->labelformat =
85
0
        (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DEFAULT) + 1);
86
0
    pInfo->ilabeltype = (int)lpDefault;
87
0
    strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DEFAULT);
88
0
  } else if (strcmp(pInfo->labelformat, "DDMMSS") == 0) {
89
0
    msFree(pInfo->labelformat);
90
0
    pInfo->labelformat =
91
0
        (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DDMMSS) + 1);
92
0
    pInfo->ilabeltype = (int)lpDDMMSS;
93
0
    strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DDMMSS);
94
0
  } else if (strcmp(pInfo->labelformat, "DDMM") == 0) {
95
0
    msFree(pInfo->labelformat);
96
0
    pInfo->labelformat =
97
0
        (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DDMM) + 1);
98
0
    pInfo->ilabeltype = (int)lpDDMM;
99
0
    strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DDMM);
100
0
  } else if (strcmp(pInfo->labelformat, "DD") == 0) {
101
0
    msFree(pInfo->labelformat);
102
0
    pInfo->labelformat =
103
0
        (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DD) + 1);
104
0
    pInfo->ilabeltype = (int)lpDD;
105
0
    strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DD);
106
0
  }
107
108
0
  return MS_SUCCESS;
109
0
}
110
111
/**********************************************************************************************************************
112
 * Return MS_TRUE if layer is open, MS_FALSE otherwise.
113
 */
114
0
int msGraticuleLayerIsOpen(layerObj *layer) {
115
0
  if (layer->grid)
116
0
    return MS_TRUE;
117
118
0
  return MS_FALSE;
119
0
}
120
121
/**********************************************************************************************************************
122
 *
123
 */
124
0
int msGraticuleLayerClose(layerObj *layer) {
125
0
  (void)layer;
126
0
  return MS_SUCCESS;
127
0
}
128
129
/**********************************************************************************************************************
130
 *
131
 */
132
0
int msGraticuleLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
133
0
  (void)isQuery;
134
0
  graticuleObj *pInfo = layer->grid;
135
0
  int iAxisTickCount = 0;
136
0
  rectObj rectMapCoordinates;
137
138
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
139
0
    return MS_FAILURE;
140
141
0
  pInfo->dstartlatitude = rect.miny;
142
0
  pInfo->dstartlongitude = rect.minx;
143
0
  pInfo->dendlatitude = rect.maxy;
144
0
  pInfo->dendlongitude = rect.maxx;
145
0
  pInfo->bvertical = 1;
146
0
  pInfo->extent = rect;
147
148
0
  if (pInfo->minincrement > 0.0) {
149
0
    pInfo->dincrementlongitude = pInfo->minincrement;
150
0
    pInfo->dincrementlatitude = pInfo->minincrement;
151
0
  } else if (pInfo->maxincrement > 0.0) {
152
0
    pInfo->dincrementlongitude = pInfo->maxincrement;
153
0
    pInfo->dincrementlatitude = pInfo->maxincrement;
154
0
  } else {
155
0
    pInfo->dincrementlongitude = 0;
156
0
    pInfo->dincrementlatitude = 0;
157
0
  }
158
159
0
  if (pInfo->maxarcs > 0)
160
0
    iAxisTickCount = (int)pInfo->maxarcs;
161
0
  else if (pInfo->minarcs > 0)
162
0
    iAxisTickCount = (int)pInfo->minarcs;
163
164
0
  DefineAxis(iAxisTickCount, &pInfo->dstartlongitude, &pInfo->dendlongitude,
165
0
             &pInfo->dincrementlongitude);
166
0
  DefineAxis(iAxisTickCount, &pInfo->dstartlatitude, &pInfo->dendlatitude,
167
0
             &pInfo->dincrementlatitude);
168
169
0
  pInfo->dwhichlatitude = pInfo->dstartlatitude;
170
0
  pInfo->dwhichlongitude = pInfo->dstartlongitude;
171
172
0
  if (pInfo->minincrement > 0.0 && pInfo->maxincrement > 0.0 &&
173
0
      pInfo->minincrement == pInfo->maxincrement) {
174
0
    pInfo->dincrementlongitude = pInfo->minincrement;
175
0
    pInfo->dincrementlatitude = pInfo->minincrement;
176
0
  } else if (pInfo->minincrement > 0.0) {
177
0
    pInfo->dincrementlongitude = pInfo->minincrement;
178
0
    pInfo->dincrementlatitude = pInfo->minincrement;
179
0
  } else if (pInfo->maxincrement > 0.0) {
180
0
    pInfo->dincrementlongitude = pInfo->maxincrement;
181
0
    pInfo->dincrementlatitude = pInfo->maxincrement;
182
0
  }
183
184
  /*
185
   * If using PROJ, project rect back into map system, and generate rect corner
186
   * points in native system. These lines will be used when generating labels to
187
   * get correct placement at arc/rect edge intersections.
188
   */
189
0
  rectMapCoordinates = layer->map->extent;
190
191
0
  layer->project =
192
0
      msProjectionsDiffer(&(layer->projection), &(layer->map->projection));
193
0
  if (layer->project && strstr(layer->map->projection.args[0], "epsg:3857") &&
194
0
      msProjIsGeographicCRS(&(layer->projection))) {
195
0
    if (rectMapCoordinates.minx < -20037508)
196
0
      rectMapCoordinates.minx = -20037508;
197
0
    if (rectMapCoordinates.maxx > 20037508)
198
0
      rectMapCoordinates.maxx = 20037508;
199
0
  }
200
201
0
  msFree(pInfo->pboundinglines);
202
0
  pInfo->pboundinglines = (lineObj *)msSmallMalloc(sizeof(lineObj) * 4);
203
0
  msFree(pInfo->pboundingpoints);
204
0
  pInfo->pboundingpoints = (pointObj *)msSmallMalloc(sizeof(pointObj) * 8);
205
206
0
  {
207
208
    /*
209
     * top
210
     */
211
0
    pInfo->pboundinglines[0].numpoints = 2;
212
0
    pInfo->pboundinglines[0].point = &pInfo->pboundingpoints[0];
213
0
    pInfo->pboundinglines[0].point[0].x = rectMapCoordinates.minx;
214
0
    pInfo->pboundinglines[0].point[0].y = rectMapCoordinates.maxy;
215
0
    pInfo->pboundinglines[0].point[1].x = rectMapCoordinates.maxx;
216
0
    pInfo->pboundinglines[0].point[1].y = rectMapCoordinates.maxy;
217
218
0
    if (layer->project)
219
0
      msProjectLine(&layer->map->projection, &layer->projection,
220
0
                    &pInfo->pboundinglines[0]);
221
222
    /*
223
     * bottom
224
     */
225
0
    pInfo->pboundinglines[1].numpoints = 2;
226
0
    pInfo->pboundinglines[1].point = &pInfo->pboundingpoints[2];
227
0
    pInfo->pboundinglines[1].point[0].x = rectMapCoordinates.minx;
228
0
    pInfo->pboundinglines[1].point[0].y = rectMapCoordinates.miny;
229
0
    pInfo->pboundinglines[1].point[1].x = rectMapCoordinates.maxx;
230
0
    pInfo->pboundinglines[1].point[1].y = rectMapCoordinates.miny;
231
232
0
    if (layer->project)
233
0
      msProjectLine(&layer->map->projection, &layer->projection,
234
0
                    &pInfo->pboundinglines[1]);
235
236
    /*
237
     * left
238
     */
239
0
    pInfo->pboundinglines[2].numpoints = 2;
240
0
    pInfo->pboundinglines[2].point = &pInfo->pboundingpoints[4];
241
0
    pInfo->pboundinglines[2].point[0].x = rectMapCoordinates.minx;
242
0
    pInfo->pboundinglines[2].point[0].y = rectMapCoordinates.miny;
243
0
    pInfo->pboundinglines[2].point[1].x = rectMapCoordinates.minx;
244
0
    pInfo->pboundinglines[2].point[1].y = rectMapCoordinates.maxy;
245
246
0
    if (layer->project)
247
0
      msProjectLine(&layer->map->projection, &layer->projection,
248
0
                    &pInfo->pboundinglines[2]);
249
250
    /*
251
     * right
252
     */
253
0
    pInfo->pboundinglines[3].numpoints = 2;
254
0
    pInfo->pboundinglines[3].point = &pInfo->pboundingpoints[6];
255
0
    pInfo->pboundinglines[3].point[0].x = rectMapCoordinates.maxx;
256
0
    pInfo->pboundinglines[3].point[0].y = rectMapCoordinates.miny;
257
0
    pInfo->pboundinglines[3].point[1].x = rectMapCoordinates.maxx;
258
0
    pInfo->pboundinglines[3].point[1].y = rectMapCoordinates.maxy;
259
260
0
    if (layer->project)
261
0
      msProjectLine(&layer->map->projection, &layer->projection,
262
0
                    &pInfo->pboundinglines[3]);
263
0
  }
264
265
0
  return MS_SUCCESS;
266
0
}
267
268
/**********************************************************************************************************************
269
 *
270
 */
271
0
int msGraticuleLayerNextShape(layerObj *layer, shapeObj *shape) {
272
0
  graticuleObj *pInfo = layer->grid;
273
274
0
  if (pInfo->minsubdivides <= 0.0 || pInfo->maxsubdivides <= 0.0)
275
0
    pInfo->minsubdivides = pInfo->maxsubdivides =
276
0
        MAPGRATICULE_ARC_SUBDIVISION_DEFAULT;
277
278
0
  shape->numlines = 1;
279
0
  shape->type = MS_SHAPE_LINE;
280
0
  shape->line = (lineObj *)msSmallMalloc(sizeof(lineObj));
281
0
  shape->line->numpoints = (int)pInfo->maxsubdivides;
282
0
  shape->line->point = NULL;
283
284
  /*
285
   * Subdivide and draw current arc, rendering the arc labels first
286
   */
287
0
  if (pInfo->bvertical) {
288
0
    int iPointIndex;
289
0
    double dArcDelta = (pInfo->dendlatitude - pInfo->dstartlatitude) /
290
0
                       (double)shape->line->numpoints;
291
0
    double dArcPosition = pInfo->dstartlatitude + dArcDelta;
292
0
    double dStartY, dDeltaX;
293
294
0
    switch (pInfo->ilabelstate) {
295
0
    case 0:
296
0
      if (!pInfo->blabelaxes) { /* Bottom */
297
0
        pInfo->ilabelstate++;
298
0
        msFreeShape(shape);
299
0
        return MS_SUCCESS;
300
0
      }
301
302
0
      dDeltaX = (pInfo->dwhichlongitude - pInfo->pboundinglines[1].point[0].x) /
303
0
                (pInfo->pboundinglines[1].point[1].x -
304
0
                 pInfo->pboundinglines[1].point[0].x);
305
0
      if (dDeltaX < 0)
306
0
        dDeltaX = dDeltaX * -1;
307
308
0
      dStartY = (pInfo->pboundinglines[1].point[1].y -
309
0
                 pInfo->pboundinglines[1].point[0].y) *
310
0
                    dDeltaX +
311
0
                pInfo->pboundinglines[1].point[0].y;
312
0
      shape->line->numpoints = (int)2;
313
0
      shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2);
314
315
0
      shape->line->point[0].x = pInfo->dwhichlongitude;
316
0
      shape->line->point[0].y = dStartY;
317
0
      shape->line->point[1].x = pInfo->dwhichlongitude;
318
0
      shape->line->point[1].y = dStartY + dArcDelta;
319
320
0
      _FormatLabel(layer, shape, shape->line->point[0].x);
321
0
      if (_AdjustLabelPosition(layer, shape, posBottom) != MS_SUCCESS) {
322
0
        msFreeShape(shape);
323
0
        pInfo->ilabelstate++;
324
0
        return MS_SUCCESS;
325
0
      }
326
327
0
      pInfo->ilabelstate++;
328
0
      return MS_SUCCESS;
329
330
0
    case 1:
331
0
      if (!pInfo->blabelaxes) { /* Top */
332
0
        pInfo->ilabelstate++;
333
0
        msFreeShape(shape);
334
0
        return MS_SUCCESS;
335
0
      }
336
337
0
      dDeltaX = (pInfo->dwhichlongitude - pInfo->pboundinglines[0].point[0].x) /
338
0
                (pInfo->pboundinglines[0].point[1].x -
339
0
                 pInfo->pboundinglines[0].point[0].x);
340
0
      if (dDeltaX < 0)
341
0
        dDeltaX = dDeltaX * -1;
342
343
0
      dStartY = (pInfo->pboundinglines[0].point[1].y -
344
0
                 pInfo->pboundinglines[0].point[0].y) *
345
0
                    dDeltaX +
346
0
                pInfo->pboundinglines[0].point[1].y;
347
0
      shape->line->numpoints = (int)2;
348
0
      shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2);
349
350
0
      shape->line->point[0].x = pInfo->dwhichlongitude;
351
0
      shape->line->point[0].y = dStartY - dArcDelta;
352
0
      shape->line->point[1].x = pInfo->dwhichlongitude;
353
0
      shape->line->point[1].y = dStartY;
354
355
0
      _FormatLabel(layer, shape, shape->line->point[0].x);
356
0
      if (_AdjustLabelPosition(layer, shape, posTop) != MS_SUCCESS) {
357
0
        msFreeShape(shape);
358
0
        pInfo->ilabelstate++;
359
0
        return MS_SUCCESS;
360
0
      }
361
362
0
      pInfo->ilabelstate++;
363
0
      return MS_SUCCESS;
364
365
0
    case 2:
366
0
      shape->line->numpoints = (int)shape->line->numpoints + 1;
367
0
      shape->line->point =
368
0
          (pointObj *)msSmallMalloc(sizeof(pointObj) * shape->line->numpoints);
369
370
0
      shape->line->point[0].x = pInfo->dwhichlongitude;
371
0
      shape->line->point[0].y = pInfo->dstartlatitude;
372
373
0
      for (iPointIndex = 1; iPointIndex < shape->line->numpoints;
374
0
           iPointIndex++) {
375
0
        shape->line->point[iPointIndex].x = pInfo->dwhichlongitude;
376
0
        shape->line->point[iPointIndex].y = dArcPosition;
377
378
0
        dArcPosition += dArcDelta;
379
0
      }
380
381
0
      pInfo->ilabelstate = 0;
382
383
0
      pInfo->dwhichlongitude += pInfo->dincrementlongitude;
384
0
      break;
385
386
0
    default:
387
0
      pInfo->ilabelstate = 0;
388
0
      break;
389
0
    }
390
391
0
  } else { /*horizontal*/
392
0
    int iPointIndex;
393
0
    double dArcDelta = (pInfo->dendlongitude - pInfo->dstartlongitude) /
394
0
                       (double)shape->line->numpoints;
395
0
    double dArcPosition = pInfo->dstartlongitude + dArcDelta;
396
0
    double dStartX, dDeltaY;
397
398
0
    switch (pInfo->ilabelstate) {
399
0
    case 0:
400
0
      if (!pInfo->blabelaxes) { /* Left side */
401
0
        pInfo->ilabelstate++;
402
0
        msFreeShape(shape);
403
0
        return MS_SUCCESS;
404
0
      }
405
406
0
      dDeltaY = (pInfo->dwhichlatitude - pInfo->pboundinglines[2].point[0].y) /
407
0
                (pInfo->pboundinglines[2].point[1].y -
408
0
                 pInfo->pboundinglines[2].point[0].y);
409
0
      if (dDeltaY < 0)
410
0
        dDeltaY = dDeltaY * -1;
411
412
0
      dStartX = (pInfo->pboundinglines[2].point[1].x -
413
0
                 pInfo->pboundinglines[2].point[0].x) *
414
0
                    dDeltaY +
415
0
                pInfo->pboundinglines[2].point[0].x;
416
0
      shape->line->numpoints = (int)2;
417
0
      shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2);
418
419
0
      shape->line->point[0].x = dStartX;
420
0
      shape->line->point[0].y = pInfo->dwhichlatitude;
421
0
      shape->line->point[1].x = dStartX + dArcDelta;
422
0
      shape->line->point[1].y = pInfo->dwhichlatitude;
423
424
0
      _FormatLabel(layer, shape, shape->line->point[0].y);
425
0
      if (_AdjustLabelPosition(layer, shape, posLeft) != MS_SUCCESS) {
426
0
        msFreeShape(shape);
427
0
        pInfo->ilabelstate++;
428
0
        return MS_SUCCESS;
429
0
      }
430
431
0
      pInfo->ilabelstate++;
432
0
      return MS_SUCCESS;
433
434
0
    case 1:
435
0
      if (!pInfo->blabelaxes) { /* Right side */
436
0
        pInfo->ilabelstate++;
437
0
        msFreeShape(shape);
438
0
        return MS_SUCCESS;
439
0
      }
440
441
0
      dDeltaY = (pInfo->dwhichlatitude - pInfo->pboundinglines[3].point[0].y) /
442
0
                (pInfo->pboundinglines[3].point[1].y -
443
0
                 pInfo->pboundinglines[3].point[0].y);
444
0
      if (dDeltaY < 0)
445
0
        dDeltaY = dDeltaY * -1;
446
447
0
      dStartX = (pInfo->pboundinglines[3].point[1].x -
448
0
                 pInfo->pboundinglines[3].point[0].x) *
449
0
                    dDeltaY +
450
0
                pInfo->pboundinglines[3].point[0].x;
451
0
      shape->line->numpoints = (int)2;
452
0
      shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2);
453
454
0
      shape->line->point[0].x = dStartX - dArcDelta;
455
0
      shape->line->point[0].y = pInfo->dwhichlatitude;
456
0
      shape->line->point[1].x = dStartX;
457
0
      shape->line->point[1].y = pInfo->dwhichlatitude;
458
459
0
      _FormatLabel(layer, shape, shape->line->point[0].y);
460
0
      if (_AdjustLabelPosition(layer, shape, posRight) != MS_SUCCESS) {
461
0
        msFreeShape(shape);
462
0
        pInfo->ilabelstate++;
463
0
        return MS_SUCCESS;
464
0
      }
465
466
0
      pInfo->ilabelstate++;
467
0
      return MS_SUCCESS;
468
469
0
    case 2:
470
0
      shape->line->numpoints = (int)shape->line->numpoints + 1;
471
0
      shape->line->point =
472
0
          (pointObj *)msSmallMalloc(sizeof(pointObj) * shape->line->numpoints);
473
474
0
      shape->line->point[0].x = pInfo->dstartlongitude;
475
0
      shape->line->point[0].y = pInfo->dwhichlatitude;
476
477
0
      for (iPointIndex = 1; iPointIndex < shape->line->numpoints;
478
0
           iPointIndex++) {
479
0
        shape->line->point[iPointIndex].x = dArcPosition;
480
0
        shape->line->point[iPointIndex].y = pInfo->dwhichlatitude;
481
482
0
        dArcPosition += dArcDelta;
483
0
      }
484
485
0
      pInfo->ilabelstate = 0;
486
0
      pInfo->dwhichlatitude += pInfo->dincrementlatitude;
487
0
      break;
488
489
0
    default:
490
0
      pInfo->ilabelstate = 0;
491
0
      break;
492
0
    }
493
0
  }
494
495
  /*
496
   * Increment and move to next arc
497
   */
498
499
0
  if (pInfo->bvertical && pInfo->dwhichlongitude > pInfo->dendlongitude) {
500
0
    pInfo->dwhichlatitude = pInfo->dstartlatitude;
501
0
    pInfo->bvertical = 0;
502
0
  }
503
504
0
  if (pInfo->dwhichlatitude > pInfo->dendlatitude) {
505
    /* free the lineObj and pointObj that have been erroneously allocated
506
     * beforehand */
507
0
    msFreeShape(shape);
508
0
    return MS_DONE;
509
0
  }
510
511
0
  return MS_SUCCESS;
512
0
}
513
514
/**********************************************************************************************************************
515
 *
516
 */
517
0
int msGraticuleLayerGetItems(layerObj *layer) {
518
0
  char **ppItemName = (char **)msSmallMalloc(sizeof(char *));
519
520
0
  *ppItemName = (char *)msSmallMalloc(64); /* why is this necessary? */
521
0
  strcpy(*ppItemName, "Graticule");
522
523
0
  layer->numitems = 1;
524
0
  layer->items = ppItemName;
525
526
0
  return MS_SUCCESS;
527
0
}
528
529
/**********************************************************************************************************************
530
 *
531
 */
532
0
int msGraticuleLayerInitItemInfo(layerObj *layer) {
533
0
  (void)layer;
534
0
  return MS_SUCCESS;
535
0
}
536
537
/**********************************************************************************************************************
538
 *
539
 */
540
0
void msGraticuleLayerFreeItemInfo(layerObj *layer) { (void)layer; }
541
542
/**********************************************************************************************************************
543
 *
544
 */
545
int msGraticuleLayerGetShape(layerObj *layer, shapeObj *shape,
546
0
                             resultObj *record) {
547
0
  (void)layer;
548
0
  (void)shape;
549
0
  (void)record;
550
0
  return MS_FAILURE;
551
0
}
552
553
/**********************************************************************************************************************
554
 *
555
 */
556
0
int msGraticuleLayerGetExtent(layerObj *layer, rectObj *extent) {
557
0
  graticuleObj *pInfo = layer->grid;
558
559
0
  if (pInfo) {
560
0
    *extent = pInfo->extent;
561
0
    return MS_SUCCESS;
562
0
  }
563
564
0
  return MS_FAILURE;
565
0
}
566
567
/**********************************************************************************************************************
568
 *
569
 */
570
int msGraticuleLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c,
571
0
                                 shapeObj *shape) {
572
0
  (void)map;
573
0
  (void)layer;
574
0
  (void)c;
575
0
  (void)shape;
576
0
  return MS_SUCCESS;
577
0
}
578
579
/************************************************************************/
580
/*                  msGraticuleLayerFreeIntersectionPoints              */
581
/*                                                                      */
582
/*      Free intersection object.                                       */
583
/************************************************************************/
584
0
void msGraticuleLayerFreeIntersectionPoints(graticuleIntersectionObj *psValue) {
585
0
  if (psValue) {
586
0
    for (int i = 0; i < psValue->nTop; i++)
587
0
      msFree(psValue->papszTopLabels[i]);
588
0
    msFree(psValue->papszTopLabels);
589
0
    msFree(psValue->pasTop);
590
591
0
    for (int i = 0; i < psValue->nBottom; i++)
592
0
      msFree(psValue->papszBottomLabels[i]);
593
0
    msFree(psValue->papszBottomLabels);
594
0
    msFree(psValue->pasBottom);
595
596
0
    for (int i = 0; i < psValue->nLeft; i++)
597
0
      msFree(psValue->papszLeftLabels[i]);
598
0
    msFree(psValue->papszLeftLabels);
599
0
    msFree(psValue->pasLeft);
600
601
0
    for (int i = 0; i < psValue->nRight; i++)
602
0
      msFree(psValue->papszRightLabels[i]);
603
0
    msFree(psValue->papszRightLabels);
604
0
    msFree(psValue->pasRight);
605
606
0
    msFree(psValue);
607
0
  }
608
0
}
609
610
/************************************************************************/
611
/*                  msGraticuleLayerInitIntersectionPoints              */
612
/*                                                                      */
613
/*      init intersection object.                                       */
614
/************************************************************************/
615
static void
616
0
msGraticuleLayerInitIntersectionPoints(graticuleIntersectionObj *psValue) {
617
0
  if (psValue) {
618
0
    psValue->nTop = 0;
619
0
    psValue->pasTop = NULL;
620
0
    psValue->papszTopLabels = NULL;
621
0
    psValue->nBottom = 0;
622
0
    psValue->pasBottom = NULL;
623
0
    psValue->papszBottomLabels = NULL;
624
0
    psValue->nLeft = 0;
625
0
    psValue->pasLeft = NULL;
626
0
    psValue->papszLeftLabels = NULL;
627
0
    psValue->nRight = 0;
628
0
    psValue->pasRight = NULL;
629
0
    psValue->papszRightLabels = NULL;
630
0
  }
631
0
}
632
633
/************************************************************************/
634
/*                  msGraticuleLayerGetIntersectionPoints               */
635
/*                                                                      */
636
/*      Utility function thar returns all intersection positions and    */
637
/*      labels (4 sides of the map) for a grid layer.                   */
638
/************************************************************************/
639
graticuleIntersectionObj *
640
0
msGraticuleLayerGetIntersectionPoints(mapObj *map, layerObj *layer) {
641
642
0
  shapeObj shapegrid, tmpshape;
643
0
  rectObj searchrect;
644
0
  int status;
645
0
  pointObj oFirstPoint;
646
0
  pointObj oLastPoint;
647
0
  lineObj oLineObj;
648
0
  rectObj cliprect;
649
0
  graticuleObj *pInfo = NULL;
650
0
  double dfTmp;
651
0
  int i = 0;
652
653
0
  if (layer->connectiontype != MS_GRATICULE)
654
0
    return NULL;
655
656
0
  pInfo = layer->grid;
657
658
  /*set cellsize if bnot already set*/
659
0
  if (map->cellsize == 0)
660
0
    map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height);
661
662
0
  if (layer->transform == MS_TRUE)
663
0
    searchrect = map->extent;
664
0
  else {
665
0
    searchrect.minx = searchrect.miny = 0;
666
0
    searchrect.maxx = map->width - 1;
667
0
    searchrect.maxy = map->height - 1;
668
0
  }
669
670
0
  if ((map->projection.numargs > 0) && (layer->projection.numargs > 0))
671
0
    msProjectRect(&map->projection, &layer->projection,
672
0
                  &searchrect); /* project the searchrect to source coords */
673
674
0
  status = msLayerOpen(layer);
675
0
  if (status != MS_SUCCESS)
676
0
    return NULL;
677
678
0
  status = msLayerWhichShapes(layer, searchrect, MS_FALSE);
679
0
  if (status == MS_DONE) { /* no overlap */
680
0
    msLayerClose(layer);
681
0
    return NULL;
682
0
  } else if (status != MS_SUCCESS) {
683
0
    msLayerClose(layer);
684
0
    return NULL;
685
0
  }
686
687
  /* step through the target shapes */
688
0
  msInitShape(&shapegrid);
689
0
  cliprect.minx = map->extent.minx - map->cellsize;
690
0
  cliprect.miny = map->extent.miny - map->cellsize;
691
0
  cliprect.maxx = map->extent.maxx + map->cellsize;
692
0
  cliprect.maxy = map->extent.maxy + map->cellsize;
693
694
  /* clip using the layer projection */
695
  /* msProjectRect(&map->projection , &layer->projection,  &cliprect); */
696
697
0
  graticuleIntersectionObj *psValues =
698
0
      (graticuleIntersectionObj *)msSmallMalloc(
699
0
          sizeof(graticuleIntersectionObj));
700
0
  msGraticuleLayerInitIntersectionPoints(psValues);
701
702
0
  while ((status = msLayerNextShape(layer, &shapegrid)) == MS_SUCCESS) {
703
    /*don't really need a class here*/
704
    /*
705
      shapegrid.classindex = msShapeGetClass(layer, &shapegrid, map->scaledenom,
706
    NULL, 0); if((shapegrid.classindex == -1) ||
707
    (layer->class[shapegrid.classindex]->status == MS_OFF)) {
708
    msFreeShape(&shapegrid);
709
    continue;
710
    }
711
    */
712
713
0
    msInitShape(&tmpshape);
714
0
    msCopyShape(&shapegrid, &tmpshape);
715
    /* status = msDrawShape(map, layer, &tmpshape, image, -1); */
716
717
0
    if (layer->project) {
718
0
      if (layer->reprojectorLayerToMap == NULL) {
719
0
        layer->reprojectorLayerToMap =
720
0
            msProjectCreateReprojector(&layer->projection, &map->projection);
721
0
      }
722
0
      if (layer->reprojectorLayerToMap)
723
0
        msProjectShapeEx(layer->reprojectorLayerToMap, &shapegrid);
724
0
    }
725
726
0
    msClipPolylineRect(&shapegrid, cliprect);
727
728
0
    msTransformShapeToPixelRound(&shapegrid, map->extent, map->cellsize);
729
730
0
    if (shapegrid.numlines <= 0 ||
731
0
        shapegrid.line[0].numpoints <
732
0
            2) { /* once clipped the shape didn't need to be drawn */
733
0
      msFreeShape(&shapegrid);
734
0
      msFreeShape(&tmpshape);
735
0
      continue;
736
0
    }
737
738
0
    {
739
0
      int iTmpLine = 0;
740
0
      int nNumPoints = 0;
741
      /*grid code seems to return lines that can double cross the extenst??*/
742
      /*creating a more than one clipped shape. Take the shape that has the most
743
        points, which should be the most likley to be correct*/
744
745
0
      if (shapegrid.numlines > 1) {
746
0
        for (i = 0; i < shapegrid.numlines; i++) {
747
0
          if (shapegrid.line[i].numpoints > nNumPoints) {
748
0
            nNumPoints = shapegrid.line[i].numpoints;
749
0
            iTmpLine = i;
750
0
          }
751
0
        }
752
0
      }
753
      /* get the first and last point*/
754
0
      oFirstPoint.x = shapegrid.line[iTmpLine].point[0].x;
755
0
      oFirstPoint.y = shapegrid.line[iTmpLine].point[0].y;
756
0
      oLineObj = shapegrid.line[iTmpLine];
757
0
      oLastPoint.x = oLineObj.point[oLineObj.numpoints - 1].x;
758
0
      oLastPoint.y = oLineObj.point[oLineObj.numpoints - 1].y;
759
760
0
      if (pInfo->bvertical) { /*vertical*/
761
        /*SHAPES ARE DRAWN FROM BOTTOM TO TOP.*/
762
        /*Normally lines are drawn FROM BOTTOM TO TOP but not always for some
763
        reason, so make sure that firstpoint < lastpoint in y, We are in pixel
764
        coordinates so y increases as we we go down*/
765
0
        if (oFirstPoint.y < oLastPoint.y) {
766
0
          dfTmp = oFirstPoint.x;
767
0
          oFirstPoint.x = oLastPoint.x;
768
0
          oLastPoint.x = dfTmp;
769
0
          dfTmp = oFirstPoint.y;
770
0
          oFirstPoint.y = oLastPoint.y;
771
0
          oLastPoint.y = dfTmp;
772
0
        }
773
774
        /*first point should cross the BOTTOM base where y== map->height*/
775
776
0
        if (abs((int)oFirstPoint.y - map->height) <= 1) {
777
0
          char *pszLabel = NULL;
778
0
          oFirstPoint.y = map->height;
779
780
          /*validate point is in map width/height*/
781
0
          if (oFirstPoint.x < 0 || oFirstPoint.x > map->width)
782
0
            continue;
783
784
          /*validate point is in map width/height*/
785
0
          if (oLastPoint.x < 0 || oLastPoint.x > map->width)
786
0
            continue;
787
788
0
          if (shapegrid.text)
789
0
            pszLabel = msStrdup(shapegrid.text);
790
0
          else {
791
0
            _FormatLabel(
792
0
                layer, &tmpshape,
793
0
                tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].x);
794
0
            if (tmpshape.text)
795
0
              pszLabel = msStrdup(tmpshape.text);
796
0
            else
797
0
              pszLabel = msStrdup("unknown");
798
0
          }
799
          /*validate that the  value is not already in the array*/
800
0
          if (psValues->nBottom > 0) {
801
            /* if (psValues->pasBottom[psValues->nBottom-1].x == oFirstPoint.x)
802
                 continue; */
803
804
0
            for (i = 0; i < psValues->nBottom; i++) {
805
0
              if (psValues->pasBottom[i].x == oFirstPoint.x)
806
0
                break;
807
0
            }
808
0
            if (i < psValues->nBottom) {
809
0
              msFree(pszLabel);
810
0
              continue;
811
0
            }
812
0
          }
813
0
          if (psValues->pasBottom == NULL) {
814
0
            psValues->pasBottom = (pointObj *)msSmallMalloc(sizeof(pointObj));
815
0
            psValues->papszBottomLabels =
816
0
                (char **)msSmallMalloc(sizeof(char *));
817
0
            psValues->nBottom = 1;
818
0
          } else {
819
0
            psValues->nBottom++;
820
0
            psValues->pasBottom = (pointObj *)msSmallRealloc(
821
0
                psValues->pasBottom, sizeof(pointObj) * psValues->nBottom);
822
0
            psValues->papszBottomLabels =
823
0
                (char **)msSmallRealloc(psValues->papszBottomLabels,
824
0
                                        sizeof(char *) * psValues->nBottom);
825
0
          }
826
827
0
          psValues->pasBottom[psValues->nBottom - 1].x = oFirstPoint.x;
828
0
          psValues->pasBottom[psValues->nBottom - 1].y = oFirstPoint.y;
829
0
          psValues->papszBottomLabels[psValues->nBottom - 1] = pszLabel;
830
0
        }
831
        /*first point should cross the TOP base where y==0*/
832
0
        if (abs((int)oLastPoint.y) <= 1) {
833
0
          char *pszLabel = NULL;
834
0
          oLastPoint.y = 0;
835
836
          /*validate point is in map width/height*/
837
0
          if (oLastPoint.x < 0 || oLastPoint.x > map->width)
838
0
            continue;
839
840
0
          if (shapegrid.text)
841
0
            pszLabel = msStrdup(shapegrid.text);
842
0
          else {
843
0
            _FormatLabel(
844
0
                layer, &tmpshape,
845
0
                tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].x);
846
0
            if (tmpshape.text)
847
0
              pszLabel = msStrdup(tmpshape.text);
848
0
            else
849
0
              pszLabel = msStrdup("unknown");
850
0
          }
851
          /*validate if same value is not already there*/
852
0
          if (psValues->nTop > 0) {
853
            /* if (psValues->pasTop[psValues->nTop-1].x == oLastPoint.x)
854
                 continue; */
855
856
0
            for (i = 0; i < psValues->nTop; i++) {
857
0
              if (psValues->pasTop[i].x == oLastPoint.x ||
858
0
                  strcasecmp(pszLabel, psValues->papszTopLabels[i]) == 0)
859
0
                break;
860
0
            }
861
0
            if (i < psValues->nTop) {
862
0
              msFree(pszLabel);
863
0
              continue;
864
0
            }
865
0
          }
866
867
0
          if (psValues->pasTop == NULL) {
868
0
            psValues->pasTop = (pointObj *)msSmallMalloc(sizeof(pointObj));
869
0
            psValues->papszTopLabels = (char **)msSmallMalloc(sizeof(char *));
870
0
            psValues->nTop = 1;
871
0
          } else {
872
0
            psValues->nTop++;
873
0
            psValues->pasTop = (pointObj *)msSmallRealloc(
874
0
                psValues->pasTop, sizeof(pointObj) * psValues->nTop);
875
0
            psValues->papszTopLabels = (char **)msSmallRealloc(
876
0
                psValues->papszTopLabels, sizeof(char *) * psValues->nTop);
877
0
          }
878
879
0
          psValues->pasTop[psValues->nTop - 1].x = oLastPoint.x;
880
0
          psValues->pasTop[psValues->nTop - 1].y = oLastPoint.y;
881
0
          psValues->papszTopLabels[psValues->nTop - 1] = pszLabel;
882
0
        }
883
0
      } else { /*horizontal*/
884
        /*Normally lines are drawn from left to right but not always for some
885
          reason, so make sure that firstpoint < lastpoint in x*/
886
0
        if (oFirstPoint.x > oLastPoint.x) {
887
888
0
          dfTmp = oFirstPoint.x;
889
0
          oFirstPoint.x = oLastPoint.x;
890
0
          oLastPoint.x = dfTmp;
891
0
          dfTmp = oFirstPoint.y;
892
0
          oFirstPoint.y = oLastPoint.y;
893
0
          oLastPoint.y = dfTmp;
894
0
        }
895
        /*first point should cross the LEFT base where x=0 axis*/
896
0
        if (abs((int)oFirstPoint.x) <= 1) {
897
0
          char *pszLabel = NULL;
898
0
          oFirstPoint.x = 0;
899
900
          /*validate point is in map width/height*/
901
0
          if (oFirstPoint.y < 0 || oFirstPoint.y > map->height)
902
0
            continue;
903
904
0
          if (shapegrid.text)
905
0
            pszLabel = msStrdup(shapegrid.text);
906
0
          else {
907
0
            _FormatLabel(
908
0
                layer, &tmpshape,
909
0
                tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].y);
910
0
            if (tmpshape.text)
911
0
              pszLabel = msStrdup(tmpshape.text);
912
0
            else
913
0
              pszLabel = msStrdup("unknown");
914
0
          }
915
916
          /*validate that the previous value is not the same*/
917
0
          if (psValues->nLeft > 0) {
918
            /* if (psValues->pasLeft[psValues->nLeft-1].y == oFirstPoint.y)
919
                 continue; */
920
921
0
            for (i = 0; i < psValues->nLeft; i++) {
922
0
              if (psValues->pasLeft[i].y == oFirstPoint.y)
923
0
                break;
924
0
            }
925
0
            if (i < psValues->nLeft) {
926
0
              msFree(pszLabel);
927
0
              continue;
928
0
            }
929
0
          }
930
0
          if (psValues->pasLeft == NULL) {
931
0
            psValues->pasLeft = (pointObj *)msSmallMalloc(sizeof(pointObj));
932
0
            psValues->papszLeftLabels = (char **)msSmallMalloc(sizeof(char *));
933
0
            psValues->nLeft = 1;
934
0
          } else {
935
0
            psValues->nLeft++;
936
0
            psValues->pasLeft = (pointObj *)msSmallRealloc(
937
0
                psValues->pasLeft, sizeof(pointObj) * psValues->nLeft);
938
0
            psValues->papszLeftLabels = (char **)msSmallRealloc(
939
0
                psValues->papszLeftLabels, sizeof(char *) * psValues->nLeft);
940
0
          }
941
942
0
          psValues->pasLeft[psValues->nLeft - 1].x = oFirstPoint.x;
943
0
          psValues->pasLeft[psValues->nLeft - 1].y = oFirstPoint.y;
944
0
          psValues->papszLeftLabels[psValues->nLeft - 1] =
945
0
              pszLabel; /* takes ownership of allocated pszLabel */
946
0
        }
947
        /*first point should cross the RIGHT base where x=map=>width axis*/
948
0
        if (abs((int)oLastPoint.x - map->width) <= 1) {
949
0
          char *pszLabel = NULL;
950
0
          oLastPoint.x = map->width;
951
952
          /*validate point is in map width/height*/
953
0
          if (oLastPoint.y < 0 || oLastPoint.y > map->height)
954
0
            continue;
955
956
0
          if (shapegrid.text)
957
0
            pszLabel = msStrdup(shapegrid.text);
958
0
          else {
959
0
            _FormatLabel(
960
0
                layer, &tmpshape,
961
0
                tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].y);
962
0
            if (tmpshape.text)
963
0
              pszLabel = msStrdup(tmpshape.text);
964
0
            else
965
0
              pszLabel = msStrdup("unknown");
966
0
          }
967
968
          /*validate that the previous value is not the same*/
969
0
          if (psValues->nRight > 0) {
970
            /* if (psValues->pasRight[psValues->nRight-1].y == oLastPoint.y)
971
                 continue; */
972
0
            for (i = 0; i < psValues->nRight; i++) {
973
0
              if (psValues->pasRight[i].y == oLastPoint.y)
974
0
                break;
975
0
            }
976
0
            if (i < psValues->nRight) {
977
0
              msFree(pszLabel);
978
0
              continue;
979
0
            }
980
0
          }
981
0
          if (psValues->pasRight == NULL) {
982
0
            psValues->pasRight = (pointObj *)msSmallMalloc(sizeof(pointObj));
983
0
            psValues->papszRightLabels = (char **)msSmallMalloc(sizeof(char *));
984
0
            psValues->nRight = 1;
985
0
          } else {
986
0
            psValues->nRight++;
987
0
            psValues->pasRight = (pointObj *)msSmallRealloc(
988
0
                psValues->pasRight, sizeof(pointObj) * psValues->nRight);
989
0
            psValues->papszRightLabels = (char **)msSmallRealloc(
990
0
                psValues->papszRightLabels, sizeof(char *) * psValues->nRight);
991
0
          }
992
993
0
          psValues->pasRight[psValues->nRight - 1].x = oLastPoint.x;
994
0
          psValues->pasRight[psValues->nRight - 1].y = oLastPoint.y;
995
0
          psValues->papszRightLabels[psValues->nRight - 1] = pszLabel;
996
0
        }
997
0
      }
998
0
      msFreeShape(&shapegrid);
999
0
      msFreeShape(&tmpshape);
1000
0
    }
1001
0
    msInitShape(&shapegrid);
1002
0
  }
1003
0
  msLayerClose(layer);
1004
0
  return psValues;
1005
0
}
1006
1007
/**********************************************************************************************************************
1008
 *
1009
 */
1010
0
int msGraticuleLayerInitializeVirtualTable(layerObj *layer) {
1011
0
  assert(layer != NULL);
1012
0
  assert(layer->vtable != NULL);
1013
1014
0
  layer->vtable->LayerInitItemInfo =
1015
0
      msGraticuleLayerInitItemInfo; /* should use defaults for item info
1016
                                       functions */
1017
0
  layer->vtable->LayerFreeItemInfo = msGraticuleLayerFreeItemInfo;
1018
0
  layer->vtable->LayerOpen = msGraticuleLayerOpen;
1019
0
  layer->vtable->LayerIsOpen = msGraticuleLayerIsOpen;
1020
0
  layer->vtable->LayerWhichShapes = msGraticuleLayerWhichShapes;
1021
0
  layer->vtable->LayerNextShape = msGraticuleLayerNextShape;
1022
  /* layer->vtable->LayerResultsGetShape, use default */
1023
0
  layer->vtable->LayerGetShape = msGraticuleLayerGetShape;
1024
  /* layer->vtable->LayerGetShapeCount, use default */
1025
0
  layer->vtable->LayerClose = msGraticuleLayerClose;
1026
0
  layer->vtable->LayerGetItems = msGraticuleLayerGetItems;
1027
0
  layer->vtable->LayerGetExtent = msGraticuleLayerGetExtent;
1028
0
  layer->vtable->LayerGetAutoStyle = msGraticuleLayerGetAutoStyle;
1029
0
  /* layer->vtable->LayerCloseConnection, use default */;
1030
0
  layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter;
1031
  /* layer->vtable->LayerApplyFilterToLayer, use default */
1032
  /* layer->vtable->LayerCreateItems, use default */
1033
  /* layer->vtable->LayerGetNumFeatures, use default */
1034
1035
0
  return MS_SUCCESS;
1036
0
}
1037
1038
/**********************************************************************************************************************
1039
 *
1040
 */
1041
static void _FormatLabel(layerObj *pLayer, shapeObj *pShape,
1042
0
                         double dDataToFormat) {
1043
0
  graticuleObj *pInfo = pLayer->grid;
1044
0
  char cBuffer[32];
1045
0
  int iDegrees, iMinutes;
1046
1047
0
  switch (pInfo->ilabeltype) {
1048
0
  case lpDDMMSS:
1049
0
    iDegrees = (int)dDataToFormat;
1050
0
    dDataToFormat = fabs(dDataToFormat - (double)iDegrees);
1051
0
    iMinutes = (int)(dDataToFormat * 60.0);
1052
0
    dDataToFormat = dDataToFormat - (((double)iMinutes) / 60.0);
1053
0
    sprintf(cBuffer, pInfo->labelformat, iDegrees, iMinutes,
1054
0
            (int)(dDataToFormat * 3600.0));
1055
0
    break;
1056
0
  case lpDDMM:
1057
0
    iDegrees = (int)dDataToFormat;
1058
0
    dDataToFormat = fabs(dDataToFormat - (double)iDegrees);
1059
0
    sprintf(cBuffer, pInfo->labelformat, iDegrees, (int)(dDataToFormat * 60.0));
1060
0
    break;
1061
0
  case lpDD:
1062
0
    iDegrees = (int)dDataToFormat;
1063
0
    sprintf(cBuffer, pInfo->labelformat, iDegrees);
1064
0
    break;
1065
0
  case lpDefault:
1066
0
  default:
1067
0
    sprintf(cBuffer, pInfo->labelformat, dDataToFormat);
1068
0
  }
1069
1070
0
  pShape->text = msStrdup(cBuffer);
1071
0
}
1072
1073
/**********************************************************************************************************************
1074
 *
1075
 *  Move label position into display area by adjusting underlying shape line.
1076
 */
1077
static int _AdjustLabelPosition(layerObj *pLayer, shapeObj *pShape,
1078
0
                                msGraticulePosition ePosition) {
1079
0
  graticuleObj *pInfo = pLayer->grid;
1080
0
  rectObj rectLabel;
1081
0
  pointObj ptPoint;
1082
0
  double size = -1;
1083
0
  char *labeltxt;
1084
1085
0
  if (pInfo == NULL || pShape == NULL) {
1086
0
    msSetError(MS_MISCERR,
1087
0
               "Assertion failed: Null shape or non-configured grid!, ",
1088
0
               "_AdjustLabelPosition()");
1089
0
    return MS_FAILURE;
1090
0
  }
1091
1092
0
  assert(pLayer->class[0] -> numlabels >= 1);
1093
1094
0
  if (msCheckParentPointer(pLayer->map, "map") == MS_FAILURE)
1095
0
    return MS_FAILURE;
1096
1097
0
  ptPoint = pShape->line->point[0];
1098
1099
0
  if (pLayer->project) {
1100
0
    if (pLayer->reprojectorLayerToMap == NULL) {
1101
0
      pLayer->reprojectorLayerToMap = msProjectCreateReprojector(
1102
0
          &pLayer->projection, &pLayer->map->projection);
1103
0
    }
1104
0
    if (pLayer->reprojectorLayerToMap)
1105
0
      msProjectShapeEx(pLayer->reprojectorLayerToMap, pShape);
1106
1107
    /* Poor man detection of reprojection failure */
1108
0
    if (msProjIsGeographicCRS(&(pLayer->projection)) !=
1109
0
        msProjIsGeographicCRS(&(pLayer->map->projection))) {
1110
0
      if (ptPoint.x == pShape->line->point[0].x &&
1111
0
          ptPoint.y == pShape->line->point[0].y) {
1112
0
        return MS_FAILURE;
1113
0
      }
1114
0
    }
1115
0
  }
1116
1117
0
  if (pLayer->transform) {
1118
0
    msTransformShapeToPixelRound(pShape, pLayer->map->extent,
1119
0
                                 pLayer->map->cellsize);
1120
0
  }
1121
1122
0
  size = pLayer->class[0]
1123
0
             ->labels[0]
1124
0
             ->size; /* TODO someday: adjust minsize/maxsize/resolution*/
1125
  /* We only use the first label as there's no use (yet) in defining multiple
1126
   labels for GRID layers, as the only label to represent is the longitude or
1127
   latitude */
1128
0
  labeltxt =
1129
0
      msShapeGetLabelAnnotation(pLayer, pShape, pLayer->class[0] -> labels[0]);
1130
0
  assert(labeltxt);
1131
0
  if (msGetStringSize(pLayer->map, pLayer->class[0] -> labels[0], size,
1132
0
                      labeltxt, &rectLabel) != MS_SUCCESS) {
1133
0
    free(labeltxt);
1134
0
    return MS_FAILURE; /* msSetError already called */
1135
0
  }
1136
0
  free(labeltxt);
1137
1138
0
  switch (ePosition) {
1139
0
  case posBottom:
1140
0
    pShape->line->point[1].y = pLayer->map->height;
1141
0
    pShape->line->point[0].y =
1142
0
        pLayer->map->height - (fabs(rectLabel.maxy - rectLabel.miny) * 2 + 5);
1143
0
    break;
1144
0
  case posTop:
1145
0
    pShape->line->point[1].y = 0;
1146
0
    pShape->line->point[0].y = fabs(rectLabel.maxy - rectLabel.miny) * 2 + 5;
1147
0
    break;
1148
0
  case posLeft:
1149
0
    pShape->line->point[0].x = 0;
1150
0
    pShape->line->point[1].x = fabs(rectLabel.maxx - rectLabel.minx) * 2 + 5;
1151
0
    break;
1152
0
  case posRight:
1153
0
    pShape->line->point[1].x = pLayer->map->width;
1154
0
    pShape->line->point[0].x =
1155
0
        pLayer->map->width - (fabs(rectLabel.maxx - rectLabel.minx) * 2 + 5);
1156
0
    break;
1157
0
  }
1158
1159
0
  if (pLayer->transform)
1160
0
    msTransformPixelToShape(pShape, pLayer->map->extent, pLayer->map->cellsize);
1161
1162
0
  if (pLayer->project) {
1163
    /* Clamp coordinates into the validity area of the projection, in the */
1164
    /* particular case of EPSG:3857 (WebMercator) to longlat reprojection */
1165
0
    if (strstr(pLayer->map->projection.args[0], "epsg:3857") &&
1166
0
        msProjIsGeographicCRS(&(pLayer->projection))) {
1167
0
      if (!pLayer->map->projection.gt.need_geotransform &&
1168
0
          ePosition == posLeft && pShape->line->point[0].x < -20037508) {
1169
0
        pShape->line->point[1].x =
1170
0
            -20037508 + (pShape->line->point[1].x - pShape->line->point[0].x);
1171
0
        pShape->line->point[0].x = -20037508;
1172
0
      } else if (pLayer->map->projection.gt.need_geotransform &&
1173
0
                 ePosition == posLeft &&
1174
0
                 pLayer->map->projection.gt.geotransform[0] +
1175
0
                         pShape->line->point[0].x *
1176
0
                             pLayer->map->projection.gt.geotransform[1] +
1177
0
                         pShape->line->point[0].y *
1178
0
                             pLayer->map->projection.gt.geotransform[2] <
1179
0
                     -20037508) {
1180
0
        double y_tmp;
1181
0
        double width = pShape->line->point[1].x - pShape->line->point[0].x;
1182
1183
0
        y_tmp = pLayer->map->projection.gt.geotransform[3] +
1184
0
                pShape->line->point[0].x *
1185
0
                    pLayer->map->projection.gt.geotransform[4] +
1186
0
                pShape->line->point[0].y *
1187
0
                    pLayer->map->projection.gt.geotransform[5];
1188
0
        pShape->line->point[0].x =
1189
0
            pLayer->map->projection.gt.invgeotransform[0] +
1190
0
            -20037508 * pLayer->map->projection.gt.invgeotransform[1] +
1191
0
            y_tmp * pLayer->map->projection.gt.invgeotransform[2];
1192
0
        pShape->line->point[1].x = pShape->line->point[0].x + width;
1193
0
      }
1194
1195
0
      if (!pLayer->map->projection.gt.need_geotransform &&
1196
0
          ePosition == posRight && pShape->line->point[1].x > 20037508) {
1197
0
        pShape->line->point[0].x =
1198
0
            20037508 - (pShape->line->point[1].x - pShape->line->point[0].x);
1199
0
        pShape->line->point[1].x = 20037508;
1200
0
      } else if (pLayer->map->projection.gt.need_geotransform &&
1201
0
                 ePosition == posRight &&
1202
0
                 pLayer->map->projection.gt.geotransform[0] +
1203
0
                         pShape->line->point[1].x *
1204
0
                             pLayer->map->projection.gt.geotransform[1] +
1205
0
                         pShape->line->point[1].y *
1206
0
                             pLayer->map->projection.gt.geotransform[2] >
1207
0
                     20037508) {
1208
0
        double y_tmp;
1209
0
        double width = pShape->line->point[1].x - pShape->line->point[0].x;
1210
1211
0
        y_tmp = pLayer->map->projection.gt.geotransform[3] +
1212
0
                pShape->line->point[1].x *
1213
0
                    pLayer->map->projection.gt.geotransform[4] +
1214
0
                pShape->line->point[1].y *
1215
0
                    pLayer->map->projection.gt.geotransform[5];
1216
0
        pShape->line->point[1].x =
1217
0
            pLayer->map->projection.gt.invgeotransform[0] +
1218
0
            20037508 * pLayer->map->projection.gt.invgeotransform[1] +
1219
0
            y_tmp * pLayer->map->projection.gt.invgeotransform[2];
1220
0
        pShape->line->point[0].x = pShape->line->point[1].x - width;
1221
0
      }
1222
0
    }
1223
1224
0
    if (pLayer->reprojectorMapToLayer == NULL) {
1225
0
      pLayer->reprojectorMapToLayer = msProjectCreateReprojector(
1226
0
          &pLayer->map->projection, &pLayer->projection);
1227
0
    }
1228
0
    if (pLayer->reprojectorMapToLayer)
1229
0
      msProjectShapeEx(pLayer->reprojectorMapToLayer, pShape);
1230
0
  }
1231
1232
0
  switch (ePosition) {
1233
0
  case posBottom:
1234
0
  case posTop:
1235
0
    pShape->line->point[1].x = ptPoint.x;
1236
0
    pShape->line->point[0].x = ptPoint.x;
1237
0
    break;
1238
0
  case posLeft:
1239
0
  case posRight:
1240
0
    pShape->line->point[1].y = ptPoint.y;
1241
0
    pShape->line->point[0].y = ptPoint.y;
1242
0
    break;
1243
0
  }
1244
1245
0
  return MS_SUCCESS;
1246
0
}
1247
1248
/**********************************************************************************************************************
1249
 **********************************************************************************************************************
1250
 * DefineAxes - Copyright (c) 2000, Michael P.D. Bramley.
1251
 *
1252
 * Permission is granted to use this code without restriction as long as
1253
 * this copyright notice appears in all source files.
1254
 *
1255
 * Minor tweaks to increment calculations - jnovak
1256
 */
1257
0
void DefineAxis(int iTickCountTarget, double *Min, double *Max, double *Inc) {
1258
  /* define local variables... */
1259
1260
0
  double Test_inc,         /* candidate increment value */
1261
0
      Test_min,            /* minimum scale value */
1262
0
      Test_max,            /* maximum scale value */
1263
0
      Range = *Max - *Min; /* range of data */
1264
1265
0
  int i = 0; /* counter */
1266
1267
  /* don't create problems -- solve them */
1268
1269
0
  if (Range < 0) {
1270
0
    *Inc = 0;
1271
0
    return;
1272
0
  }
1273
1274
  /* handle special case of repeated values */
1275
1276
0
  else if (Range == 0) {
1277
0
    *Min = ceil(*Max) - 1;
1278
0
    *Max = *Min + 1;
1279
0
    *Inc = 1;
1280
0
    return;
1281
0
  }
1282
1283
  /* compute candidate for increment */
1284
1285
0
  Test_inc = pow(10.0, ceil(log10(Range / 10)));
1286
0
  if (*Inc > 0 && (Test_inc < *Inc || Test_inc > *Inc))
1287
0
    Test_inc = *Inc;
1288
1289
  /* establish maximum scale value... */
1290
0
  Test_max = ((long)(*Max / Test_inc)) * Test_inc;
1291
1292
0
  if (Test_max < *Max)
1293
0
    Test_max += Test_inc;
1294
1295
  /* establish minimum scale value... */
1296
0
  Test_min = Test_max;
1297
0
  do {
1298
0
    ++i;
1299
0
    Test_min -= Test_inc;
1300
0
  } while (Test_min > *Min);
1301
1302
  /* subtracting small values can screw up the scale limits, */
1303
  /* eg: if DefineAxis is called with (min,max)=(0.01, 0.1), */
1304
  /* then the calculated scale is 1.0408E17 TO 0.05 BY 0.01. */
1305
  /* the following if statement corrects for this... */
1306
1307
  /* if(fabs(Test_min) < 1E-10) */
1308
  /* Test_min = 0 ; */
1309
1310
  /* adjust for too few tick marks */
1311
1312
0
  if (iTickCountTarget <= 0)
1313
0
    iTickCountTarget = MAPGRATICULE_ARC_MINIMUM;
1314
1315
0
  while (i < iTickCountTarget) {
1316
0
    Test_inc /= 2;
1317
0
    i *= 2;
1318
0
  }
1319
1320
0
  if (i < 6 && 0) {
1321
0
    Test_inc /= 2;
1322
0
    if ((Test_min + Test_inc) <= *Min)
1323
0
      Test_min += Test_inc;
1324
0
    if ((Test_max - Test_inc) >= *Max)
1325
0
      Test_max -= Test_inc;
1326
0
  }
1327
1328
  /* pass back axis definition to caller */
1329
1330
0
  *Min = Test_min;
1331
0
  *Max = Test_max;
1332
0
  *Inc = Test_inc;
1333
0
}
1334
1335
/**********************************************************************************************************************
1336
 **********************************************************************************************************************/