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