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