GRASS Programmer's Manual  6.4.2(2012)
gsd_legend.c
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines