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