GRASS Programmer's Manual
6.4.2(2012)
|
00001 00022 #include <stdlib.h> 00023 00024 #include <grass/config.h> 00025 00026 #if defined(OPENGL_X11) || defined(OPENGL_WINDOWS) 00027 #include <GL/gl.h> 00028 #include <GL/glu.h> 00029 #elif defined(OPENGL_AQUA) 00030 #include <OpenGL/gl.h> 00031 #include <OpenGL/glu.h> 00032 #endif 00033 00034 #include <grass/gis.h> 00035 #include <grass/glocale.h> 00036 #include <grass/gstypes.h> 00037 00038 #include "rgbpack.h" 00039 00040 static float *Listcats; 00041 static int Listnum = 0; 00042 00043 /**** TODO 00044 static int bigger(float *f1, float *f2) 00045 { 00046 return (*f1 < *f2 ? -1 : (*f1 > *f2)); 00047 } 00048 *****/ 00049 00050 #define MAX_LEGEND 256 00051 00060 void gsd_bgn_legend_viewport(GLint wl, GLint wb, GLint wr, GLint wt) 00061 { 00062 /* sets the viewport for the legend and the model matrix */ 00063 00064 gsd_colormode(CM_COLOR); 00065 glPushAttrib(GL_VIEWPORT); 00066 00067 glMatrixMode(GL_PROJECTION); 00068 00069 gsd_pushmatrix(); 00070 GS_set_draw(GSD_FRONT); 00071 GS_ready_draw(); 00072 00073 gsd_linewidth(1); 00074 00075 gsd_popmatrix(); 00076 00077 glViewport(wl, wb, (wr - wl), (wt - wb)); 00078 glLoadIdentity(); 00079 gluOrtho2D(-0.5, (wr - wl) + 0.5, -0.5, (wt - wb) + 0.5); 00080 glMatrixMode(GL_MODELVIEW); 00081 glPushMatrix(); 00082 glLoadIdentity(); 00083 00084 return; 00085 } 00086 00090 void gsd_end_legend_viewport(void) 00091 { 00092 /* closes the legend viewport and resets matrix and buffers */ 00093 00094 gsd_popmatrix(); 00095 glMatrixMode(GL_PROJECTION); 00096 gsd_popmatrix(); 00097 00098 glPopAttrib(); 00099 glMatrixMode(GL_MODELVIEW); 00100 gsd_popmatrix(); 00101 00102 GS_done_draw(); 00103 GS_set_draw(GSD_BACK); 00104 00105 return; 00106 } 00107 00119 int gsd_get_nice_range(float lownum, float highnum, int numvals, float *vals) 00120 { 00121 /* get a nice range for displaying legend */ 00122 00123 int num = 0; 00124 float curnum, step, start; 00125 00126 if (!numvals) 00127 return (0); 00128 00129 step = (highnum - lownum) / (float)numvals; 00130 gsd_make_nice_number(&step); 00131 00132 /* get a starting point */ 00133 start = step * (int)(1 + lownum / step); 00134 if (start - lownum < .65 * step) 00135 start += step; 00136 00137 for (curnum = start; curnum < (highnum - .65 * step); curnum += step) { 00138 vals[num++] = curnum; 00139 } 00140 00141 return (num); 00142 00143 } 00144 00153 int gsd_make_nice_number(float *num) 00154 { 00155 float newnum, nextnum; 00156 00157 if (*num < 0) 00158 return (0); 00159 00160 if (*num < 1) { 00161 newnum = 1.; 00162 while (.5 * newnum > *num) { 00163 nextnum = newnum / 10.; 00164 newnum /= 2.; 00165 if (.5 * newnum > *num) 00166 newnum /= 2.; 00167 if (.5 * newnum > *num) 00168 newnum = nextnum; 00169 } 00170 } 00171 else { 00172 newnum = 1.; 00173 while (2 * newnum <= *num) { 00174 nextnum = newnum * 10.; 00175 newnum *= 2.5; 00176 if (2 * newnum <= *num) 00177 newnum *= 2.; 00178 if (2 * newnum <= *num) 00179 newnum = nextnum; 00180 } 00181 if (newnum == 2.5) 00182 newnum = 3; 00183 /* 2.5 isn't nice, but .25, 25, 250 ... are */ 00184 } 00185 *num = newnum; 00186 return (1); 00187 } 00188 00201 GLuint gsd_put_legend(const char *name, GLuint fontbase, int size, int *flags, 00202 float *rangef, int *pt) 00203 { 00204 GLint sl, sr, sb, st; 00205 GLuint legend_list; 00206 int cat_labs = 0, cat_vals = 0, do_invert = 0, discrete = 0; 00207 int is_fp, fprec, iprec; 00208 struct Categories cats; 00209 struct Range range; 00210 struct FPRange fp_range; 00211 const char *mapset; 00212 struct Colors colors; 00213 CELL min, max; 00214 DCELL fmin, fmax; 00215 float labvals[12]; 00216 00217 legend_list = gsd_makelist(); 00218 gsd_bgnlist(legend_list, 1); 00219 00220 /* set coords from pt */ 00221 sl = pt[0]; 00222 sr = pt[1]; 00223 sb = pt[2]; 00224 st = pt[3]; 00225 00226 /* set legend flags */ 00227 if (flags[0]) 00228 cat_vals = 1; 00229 if (flags[1]) 00230 cat_labs = 1; 00231 if (flags[3]) 00232 discrete = 1; 00233 if (flags[2]) 00234 do_invert = 1; 00235 00236 mapset = G_find_cell2(name, ""); 00237 if (mapset == NULL) { 00238 G_warning(_("Raster map <%s> not found"), name); 00239 return (-1); 00240 } 00241 00242 is_fp = G_raster_map_is_fp(name, mapset); 00243 00244 if (G_read_colors(name, mapset, &colors) == -1) { 00245 G_warning(_("Unable to read color file of raster map <%s>"), name); 00246 return (-1); 00247 } 00248 00249 if (cat_labs) 00250 if (G_read_cats(name, mapset, &cats) == -1) { 00251 G_warning(_("Unable to read category file of raster map <%s>"), 00252 name); 00253 cat_labs = 0; 00254 } 00255 00256 00257 if (flags[4] && rangef[0] != -9999. && rangef[1] != -9999.) { 00258 fmin = rangef[0]; 00259 fmax = rangef[1]; 00260 if (!is_fp) { 00261 min = (int)fmin; 00262 max = (int)fmax; 00263 } 00264 } 00265 else { 00266 if (is_fp) { 00267 if (G_read_fp_range(name, mapset, &fp_range) != 1) { 00268 G_warning(_("Unable to read fp range of raster map <%s>"), 00269 name); 00270 return (-1); 00271 } 00272 G_get_fp_range_min_max(&fp_range, &fmin, &fmax); 00273 if (flags[4] && rangef[0] != -9999.) 00274 fmin = rangef[0]; 00275 if (flags[4] && rangef[1] != -9999.) 00276 fmax = rangef[1]; 00277 } 00278 else { 00279 if (G_read_range(name, mapset, &range) == -1) { 00280 G_warning(_("Unable to read range of raster map <%s>"), name); 00281 return (-1); 00282 } 00283 G_get_range_min_max(&range, &min, &max); 00284 if (flags[4] && rangef[0] != -9999.) 00285 min = rangef[0]; 00286 if (flags[4] && rangef[1] != -9999.) 00287 max = rangef[1]; 00288 fmin = min; 00289 fmax = max; 00290 } 00291 } 00292 00293 if (fmin == fmax) 00294 G_warning(_("Range request error for legend")); 00295 00296 /* set a reasonable precision */ 00297 if (is_fp) { 00298 float df; 00299 00300 df = fmax - fmin; 00301 if (df < .1) 00302 fprec = 6; 00303 else if (df < 1) 00304 fprec = 4; 00305 else if (df < 10) 00306 fprec = 3; 00307 else if (df < 100) 00308 fprec = 2; 00309 else 00310 fprec = 1; 00311 00312 } 00313 else { 00314 int tmp, p1, p2; 00315 00316 iprec = p1 = p2 = 1; 00317 if (max > 0) 00318 for (tmp = 1; tmp < max; tmp *= 10, p1++) ; 00319 if (min < 0) 00320 for (tmp = -1; tmp > min; tmp *= 10, p2++) ; 00321 00322 iprec = (p1 > p2 ? p1 : p2); 00323 } 00324 00325 /********* 00326 * TODO incorp lists 00327 00328 if(list && (legend_type & LT_LIST)){ 00329 Listcats = list; 00330 Listnum = nlist; 00331 qsort(Listcats, Listnum, sizeof(float), bigger); 00332 discrete = 1; 00333 } 00334 else 00335 Listnum = 0; 00336 00337 *********/ 00338 00339 00340 /* how many labels? */ 00341 /* 00342 numlabs can't be = max - min + 1 any more because of floating point 00343 maybe shouldn't allow discrete legend for floating point maps (unless list) 00344 or else check number of different values in floating point map 00345 and use each if "reasonable" 00346 gs_get_values_in_range(gs, att, low, high, values, &nvals) 00347 the nvals sent has a max number to return, nvals returned is the actual 00348 number set in values, return val is 1 on success, -1 if > max vals found 00349 00350 might need to think about doing histograms first & use same routines here 00351 could also have a LT_MOST that would limit # to some N most frequent 00352 */ 00353 00357 { 00358 int i, k, lleg, horiz; 00359 int red, green, blue; 00360 CELL tcell; 00361 DCELL tdcell, pdcell; 00362 float vert1[2], vert2[2], vert3[2], vert4[2]; 00363 float *dv1, *dv2; /* changing vertex coord */ 00364 float *sv1, *sv2; /* stable vertex coord */ 00365 float stab1, stab2; 00366 unsigned long colr; 00367 float *dividers; 00368 int labw, maxlabw, numlabs; 00369 float labpos, labpt[3]; 00370 const char *cstr; 00371 char buff[80]; 00372 GLint wt, wb, wl, wr; /* Whole legend area, not just box */ 00373 int xoff, yoff; 00374 int incr; /* for do_invert */ 00375 00376 horiz = (sr - sl > st - sb); 00377 dividers = NULL; 00378 00379 if (discrete) { 00380 numlabs = Listnum ? Listnum : max - min + 1; 00381 /* watch out for trying to display mega cats */ 00382 if (is_fp && !Listnum) { 00383 discrete = 0; /* maybe later do stats & allow if few #s */ 00384 G_warning(_("Unable to show discrete FP range (use list")); 00385 return (-1); 00386 } 00387 if (numlabs < MAX_LEGEND) 00388 dividers = (float *)G_malloc(numlabs * sizeof(float)); 00389 } 00390 else { 00391 numlabs = gsd_get_nice_range(fmin, fmax, 4, labvals + 1); 00392 labvals[0] = fmin; 00393 labvals[numlabs + 1] = fmax; 00394 numlabs += 2; 00395 } 00396 00397 /* find longest string, reset viewport & saveunder */ 00398 maxlabw = 0; 00399 00400 if (cat_labs || cat_vals) { 00401 for (k = 0; k < numlabs; k++) { 00402 if (is_fp) { 00403 tdcell = discrete ? Listcats[k] : labvals[k]; 00404 if (cat_labs) { 00405 cstr = G_get_d_raster_cat(&tdcell, &cats); 00406 } 00407 if (cat_labs && !cat_vals) { 00408 sprintf(buff, "%s", cstr); 00409 } 00410 else { 00411 if (cat_labs && cat_vals) { 00412 if (cstr) 00413 sprintf(buff, "%.*lf) %s", 00414 fprec, tdcell, cstr); 00415 else 00416 sprintf(buff, "%.*lf", fprec, tdcell); 00417 } 00418 else if (cat_vals) 00419 sprintf(buff, "%.*lf", fprec, tdcell); 00420 } 00421 } 00422 else { 00423 tcell = discrete ? Listnum ? 00424 Listcats[k] : min + k : labvals[k]; 00425 if (cat_labs && !cat_vals) 00426 sprintf(buff, "%s", G_get_cat(tcell, &cats)); 00427 else { 00428 if (cat_labs && cat_vals) { 00429 cstr = G_get_cat(tcell, &cats); 00430 if (cstr[0]) 00431 sprintf(buff, "%*d) %s", iprec, tcell, cstr); 00432 else 00433 sprintf(buff, "%d", tcell); 00434 } 00435 else if (cat_vals) 00436 sprintf(buff, "%d", tcell); 00437 } 00438 } 00439 labw = gsd_get_txtwidth(buff, size); 00440 if (labw > maxlabw) { 00441 maxlabw = labw; 00442 } 00443 } 00444 } 00445 00446 if (horiz) { 00447 xoff = maxlabw / 2 + get_txtxoffset(); 00448 wl = sl - xoff; 00449 wr = sr + xoff; 00450 yoff = 0; 00451 wb = sb; 00452 /* 00453 wt = st + gsd_get_txtheight() + get_txtdescender() +3; 00454 */ 00455 wt = st + gsd_get_txtheight(size) * 2 + 3; 00456 } 00457 else { 00458 xoff = 0; 00459 wl = sl; 00460 wr = sr + maxlabw + get_txtxoffset() + 3; 00461 /* 00462 yoff = gsd_get_txtheight()/2 + get_txtdescender(); 00463 */ 00464 yoff = gsd_get_txtheight(size); 00465 wb = sb - yoff; 00466 wt = st + yoff; 00467 } 00468 00469 /* initialize viewport */ 00470 gsd_bgn_legend_viewport(wl, wb, wr, wt); 00471 00472 00473 vert1[X] = vert2[X] = xoff; 00474 vert1[Y] = vert2[Y] = yoff; 00475 if (horiz) { 00476 lleg = sr - sl; 00477 dv1 = vert1 + X; 00478 dv2 = vert2 + X; 00479 sv1 = vert1 + Y; 00480 sv2 = vert2 + Y; 00481 stab2 = vert2[Y] = st - sb + yoff; 00482 stab1 = vert1[Y] = yoff; 00483 if (do_invert) 00484 vert1[X] = vert2[X] = sr - sl + xoff; 00485 } 00486 else { 00487 lleg = st - sb; 00488 dv1 = vert1 + Y; 00489 dv2 = vert2 + Y; 00490 sv1 = vert1 + X; 00491 sv2 = vert2 + X; 00492 stab2 = vert2[X] = sr - sl + xoff; 00493 stab1 = vert1[X] = xoff; 00494 if (do_invert) 00495 vert1[Y] = vert2[Y] = st - sb + yoff; 00496 } 00497 00498 if (discrete) { 00499 if (numlabs > lleg / 5) 00500 G_warning(_("Too many categories to show as discrete!")); 00501 else if (numlabs > 1.2 * lleg / gsd_get_txtheight(size)) 00502 G_warning(_("Try using smaller font!")); 00503 } 00504 00505 incr = do_invert ? -1 : 1; 00506 for (k = 0, i = 0; k < lleg; k++) { 00507 if (discrete && Listnum) 00508 tdcell = Listcats[(int)((float)k * numlabs / lleg)]; 00509 else { 00510 tcell = min + k * (max - min + 1) / lleg; 00511 tdcell = fmin + k * (fmax - fmin) / lleg; 00512 if (!is_fp) 00513 tdcell = tcell; 00514 } 00515 if (k == 0 || tdcell != pdcell) { 00516 if (is_fp) 00517 G_get_d_raster_color(&tdcell, 00518 &red, &green, &blue, &colors); 00519 else 00520 G_get_color((CELL) tdcell, &red, &green, &blue, &colors); 00521 00522 RGB_TO_INT(red, green, blue, colr); 00523 if (discrete) { /* draw black-white-black separator */ 00524 if (k > 0) { 00525 *dv1 -= 2. * incr; 00526 *dv2 -= 2. * incr; 00527 gsd_color_func(0x0); 00528 gsd_bgnline(); 00529 glVertex2fv(vert1); 00530 glVertex2fv(vert2); 00531 gsd_endline(); 00532 00533 *dv1 += 1. * incr; 00534 *dv2 += 1. * incr; 00535 if (dividers) 00536 dividers[i++] = *dv1; 00537 00538 *dv1 += 1. * incr; 00539 *dv2 += 1. * incr; 00540 gsd_color_func(0x0); 00541 gsd_bgnline(); 00542 glVertex2fv(vert1); 00543 glVertex2fv(vert2); 00544 gsd_endline(); 00545 00546 *dv1 += 1. * incr; 00547 *dv2 += 1. * incr; 00548 pdcell = tdcell; 00549 continue; 00550 } 00551 } 00552 } 00553 00554 gsd_color_func(colr); 00555 gsd_bgnline(); 00556 glVertex2fv(vert1); 00557 glVertex2fv(vert2); 00558 gsd_endline(); 00559 glFlush(); 00560 *dv1 += 1. * incr; 00561 *dv2 += 1. * incr; 00562 pdcell = tdcell; 00563 } 00564 00565 /* Black box */ 00566 vert1[X] = vert2[X] = 1. + xoff; 00567 vert1[Y] = vert4[Y] = 1. + yoff; 00568 vert3[X] = vert4[X] = sr - sl - 1. + xoff; 00569 vert3[Y] = vert2[Y] = st - sb - 1. + yoff; 00570 00571 gsd_color_func(0x000000); 00572 gsd_bgnline(); 00573 glVertex2fv(vert1); 00574 glVertex2fv(vert2); 00575 glVertex2fv(vert3); 00576 glVertex2fv(vert4); 00577 glVertex2fv(vert1); 00578 gsd_endline(); 00579 00580 /* White box */ 00581 vert1[X] = vert2[X] = xoff; 00582 vert1[Y] = vert4[Y] = yoff; 00583 vert3[X] = vert4[X] = sr - sl + xoff; 00584 vert3[Y] = vert2[Y] = st - sb + yoff; 00585 00586 gsd_color_func(0xFFFFFF); 00587 gsd_bgnline(); 00588 glVertex2fv(vert1); 00589 glVertex2fv(vert2); 00590 glVertex2fv(vert3); 00591 glVertex2fv(vert4); 00592 glVertex2fv(vert1); 00593 gsd_endline(); 00594 00595 /* draw discrete dividers */ 00596 if (dividers) { 00597 gsd_color_func(0xFFFFFFFF); 00598 *sv1 = stab1; 00599 *sv2 = stab2; 00600 for (k = 0; k < i; k++) { 00601 *dv1 = *dv2 = dividers[k]; 00602 gsd_bgnline(); 00603 glVertex2fv(vert1); 00604 glVertex2fv(vert2); 00605 gsd_endline(); 00606 } 00607 } 00608 00609 if (cat_labs || cat_vals) { 00610 labpt[Z] = 0; 00611 for (k = 0; k < numlabs; k++) { 00612 if (is_fp) { 00613 if (discrete && Listnum) { 00614 tdcell = Listcats[k]; 00615 labpos = (k + .5) / numlabs; 00616 } 00617 else { 00618 /* show_all not supported unless Listnum */ 00619 tdcell = labvals[k]; 00620 labpos = (tdcell - fmin) / (fmax - fmin); 00621 } 00622 } 00623 else { 00624 if (discrete && Listnum) { 00625 tcell = Listcats[k]; 00626 labpos = (k + .5) / numlabs; 00627 } 00628 else { 00629 tcell = discrete ? min + k : labvals[k]; 00630 labpos = (tcell - min + .5) / (max - min + 1); 00631 } 00632 } 00633 if (do_invert) 00634 labpos = 1. - labpos; 00635 if (cat_labs) { 00636 if (!is_fp) 00637 cstr = G_get_cat(tcell, &cats); 00638 else 00639 cstr = G_get_d_raster_cat(&tdcell, &cats); 00640 } 00641 if (cat_labs && !cat_vals) 00642 sprintf(buff, "%s", cstr); 00643 else { 00644 if (cat_labs && cat_vals) { 00645 if (cstr) 00646 if (is_fp) 00647 sprintf(buff, "%.*lf) %s", 00648 fprec, tdcell, cstr); 00649 else 00650 sprintf(buff, "%*d) %s", iprec, tcell, cstr); 00651 else if (is_fp) 00652 sprintf(buff, "%.*lf", fprec, tdcell); 00653 else 00654 sprintf(buff, "%d", tcell); 00655 } 00656 else if (cat_vals) { 00657 if (is_fp) 00658 sprintf(buff, "%.*lf", fprec, tdcell); 00659 else 00660 sprintf(buff, "%d", tcell); 00661 } 00662 } 00663 if (horiz) { 00664 labpt[X] = labpos * (sr - sl) + xoff - 00665 gsd_get_txtwidth(buff, size) / 2 - get_txtxoffset(); 00666 labpt[Y] = 00667 st - sb + yoff + 3 + gsd_get_txtheight(size) / 2; 00668 } 00669 else { 00670 labpt[X] = sr - sl + xoff + get_txtxoffset() + 3; 00671 /* 00672 labpt[Y] = labpos * (st - sb) + yoff - 00673 gsd_get_txtheight()/2 + get_txtdescender(); 00674 */ 00675 labpt[Y] = labpos * (st - sb) + yoff - 00676 gsd_get_txtheight(size); 00677 } 00678 /* set color for black text -- maybe add option for color 00679 * supplied with font ?? 00680 */ 00681 gsd_color_func(0x000000); 00682 do_label_display(fontbase, labpt, buff); 00683 } 00684 } 00685 00686 if (discrete) 00687 G_free(dividers); 00688 } 00689 00690 if (cat_labs) 00691 G_free_cats(&cats); 00692 00693 G_free_colors(&colors); 00694 00695 gsd_end_legend_viewport(); 00696 00697 /* 00698 gsd_unset_font(fontbase); 00699 */ 00700 00701 gsd_endlist(); 00702 00703 return (legend_list); 00704 }