main.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. /* d.legend a.k.a d.leg.thin
  2. *
  3. * MODULE: d.legend
  4. *
  5. * Based on the old d.leg.thin, which replaced an even older
  6. * module called "d.legend".
  7. *
  8. * PURPOSE: Draw a graphical legend for a raster on the display mon
  9. *
  10. * AUTHORS:
  11. * Original version:
  12. * Bill Brown, U.S. Army Construction Engineering Research Laboratories
  13. * FP Support:
  14. * Radim Blazek
  15. * Merge of original "d.legend" code into d.leg.thin (now this module):
  16. * Markus Neteler
  17. * Late 2002: Rewrite of much of the code:
  18. * Hamish Bowman, Otago University, New Zealand
  19. *
  20. * COPYRIGHT: (c) 2006 The GRASS Development Team
  21. *
  22. * This program is free software under the GNU General Public
  23. * License (>=v2). Read the file COPYING that comes with GRASS
  24. * for details.
  25. *
  26. */
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <math.h>
  30. #include <grass/gis.h>
  31. #include <grass/raster.h>
  32. #include <grass/display.h>
  33. #include <grass/glocale.h>
  34. #include "local_proto.h"
  35. int main(int argc, char **argv)
  36. {
  37. char buff[512];
  38. char *map_name;
  39. int black;
  40. int cats_num;
  41. int color;
  42. int cur_dot_row;
  43. int do_cats;
  44. int dots_per_line;
  45. int thin;
  46. int i, j, k;
  47. int lines, steps;
  48. int new_colr, fp;
  49. double t, b, l, r;
  50. int hide_catnum, hide_catstr, hide_nodata, do_smooth;
  51. char *cstr;
  52. int white;
  53. double x_box[5];
  54. double y_box[5];
  55. struct Categories cats;
  56. struct Colors colors;
  57. struct GModule *module;
  58. struct Option *opt1, *opt2, *opt4, *opt5, *opt6, *opt7, *opt8, *opt9;
  59. struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit;
  60. struct Range range;
  61. struct FPRange fprange;
  62. CELL min_ind, max_ind, null_cell;
  63. DCELL dmin, dmax, val;
  64. CELL min_colr, max_colr;
  65. DCELL min_dcolr, max_dcolr;
  66. int x0, x1, y0, y1, xyTemp;
  67. double X0, X1, Y0, Y1;
  68. int SigDigits;
  69. unsigned int MaxLabelLen;
  70. char DispFormat[5]; /* %.Xf\0 */
  71. int flip, horiz, UserRange;
  72. double UserRangeMin, UserRangeMax, UserRangeTemp;
  73. double *catlist, maxCat;
  74. int catlistCount, use_catlist;
  75. /* Initialize the GIS calls */
  76. G_gisinit(argv[0]);
  77. module = G_define_module();
  78. G_add_keyword(_("display"));
  79. G_add_keyword(_("cartography"));
  80. module->description =
  81. _("Displays a legend for a raster map in the active frame "
  82. "of the graphics monitor.");
  83. opt1 = G_define_standard_option(G_OPT_R_MAP);
  84. opt1->description = _("Name of raster map");
  85. opt2 = G_define_option();
  86. opt2->key = "color";
  87. opt2->type = TYPE_STRING;
  88. opt2->answer = DEFAULT_FG_COLOR;
  89. opt2->gisprompt = "old_color,color,color";
  90. opt2->description = _("Sets the legend's text color");
  91. opt4 = G_define_option();
  92. opt4->key = "lines";
  93. opt4->type = TYPE_INTEGER;
  94. opt4->answer = "0";
  95. opt4->options = "0-1000";
  96. opt4->description =
  97. _("Number of text lines (useful for truncating long legends)");
  98. opt4->guisection = _("Advanced");
  99. opt5 = G_define_option();
  100. opt5->key = "thin";
  101. opt5->type = TYPE_INTEGER;
  102. opt5->required = NO;
  103. opt5->answer = "1";
  104. opt5->options = "1-1000";
  105. opt5->description = _("Thinning factor (thin=10 gives cats 0,10,20...)");
  106. opt5->guisection = _("Advanced");
  107. opt6 = G_define_option();
  108. opt6->key = "labelnum";
  109. opt6->type = TYPE_INTEGER;
  110. opt6->answer = "5";
  111. opt6->options = "2-100";
  112. opt6->description = _("Number of text labels for smooth gradient legend");
  113. opt6->guisection = _("Advanced");
  114. opt7 = G_define_option();
  115. opt7->key = "at";
  116. opt7->key_desc = "bottom,top,left,right";
  117. opt7->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
  118. opt7->required = NO;
  119. opt7->options = "0-100";
  120. opt7->label =
  121. _("Placement as percentage of screen coordinates (0,0 is lower left)");
  122. opt7->description = opt7->key_desc;
  123. opt7->answer = NULL;
  124. opt8 = G_define_option();
  125. opt8->key = "use";
  126. opt8->key_desc = "catnum";
  127. opt8->type = TYPE_DOUBLE; /* string as it is fed through the parser? */
  128. opt8->required = NO;
  129. opt8->description =
  130. _("List of discrete category numbers/values for legend");
  131. opt8->multiple = YES;
  132. opt8->guisection = _("Advanced");
  133. opt9 = G_define_option();
  134. opt9->key = "range";
  135. opt9->key_desc = "min,max";
  136. opt9->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */
  137. opt9->required = NO;
  138. opt9->description =
  139. _("Use a subset of the map range for the legend (min,max)");
  140. opt9->guisection = _("Advanced");
  141. hidestr = G_define_flag();
  142. hidestr->key = 'v';
  143. hidestr->description = _("Do not show category labels");
  144. hidestr->guisection = _("Advanced");
  145. hidenum = G_define_flag();
  146. hidenum->key = 'c';
  147. hidenum->description = _("Do not show category numbers");
  148. hidenum->guisection = _("Advanced");
  149. hidenodata = G_define_flag();
  150. hidenodata->key = 'n';
  151. hidenodata->description = _("Skip categories with no label");
  152. hidenodata->guisection = _("Advanced");
  153. smooth = G_define_flag();
  154. smooth->key = 's';
  155. smooth->description = _("Draw smooth gradient");
  156. smooth->guisection = _("Advanced");
  157. flipit = G_define_flag();
  158. flipit->key = 'f';
  159. flipit->description = _("Flip legend");
  160. flipit->guisection = _("Advanced");
  161. /* Check command line */
  162. if (G_parser(argc, argv))
  163. exit(EXIT_FAILURE);
  164. map_name = opt1->answer;
  165. hide_catstr = hidestr->answer; /* note hide_catstr gets changed and re-read below */
  166. hide_catnum = hidenum->answer;
  167. hide_nodata = hidenodata->answer;
  168. do_smooth = smooth->answer;
  169. flip = flipit->answer;
  170. color = 0; /* if only to get rid of the compiler warning */
  171. if (opt2->answer != NULL) {
  172. new_colr = D_translate_color(opt2->answer);
  173. if (new_colr == 0)
  174. G_fatal_error(_("Don't know the color %s"), opt2->answer);
  175. color = new_colr;
  176. }
  177. if (opt4->answer != NULL)
  178. sscanf(opt4->answer, "%d", &lines);
  179. thin = 1;
  180. if (opt5->answer != NULL)
  181. sscanf(opt5->answer, "%d", &thin);
  182. if (!thin)
  183. thin = 1;
  184. if (opt6->answer != NULL)
  185. sscanf(opt6->answer, "%d", &steps);
  186. catlistCount = 0;
  187. if (opt8->answer != NULL) { /* should this be answerS ? */
  188. use_catlist = TRUE;
  189. catlist = (double *)G_calloc(100 + 1, sizeof(double));
  190. for (i = 0; i < 100; i++) /* fill with dummy values */
  191. catlist[i] = 1.0 * (i + 1);
  192. catlist[i] = 0;
  193. for (i = 0; (opt8->answers[i] != NULL) && i < 100; i++)
  194. catlist[i] = atof(opt8->answers[i]);
  195. catlistCount = i;
  196. }
  197. else
  198. use_catlist = FALSE;
  199. UserRange = FALSE;
  200. if (opt9->answer != NULL) { /* should this be answerS ? */
  201. sscanf(opt9->answers[0], "%lf", &UserRangeMin);
  202. sscanf(opt9->answers[1], "%lf", &UserRangeMax);
  203. UserRange = TRUE;
  204. if (UserRangeMin > UserRangeMax) {
  205. UserRangeTemp = UserRangeMax;
  206. UserRangeMax = UserRangeMin;
  207. UserRangeMin = UserRangeTemp;
  208. flip = !flip;
  209. }
  210. }
  211. if (Rast_read_colors(map_name, "", &colors) == -1)
  212. G_fatal_error(_("Color file for <%s> not available"), map_name);
  213. fp = Rast_map_is_fp(map_name, "");
  214. if (fp && !use_catlist) {
  215. do_smooth = TRUE;
  216. /* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
  217. flip = !flip;
  218. }
  219. if (Rast_read_cats(map_name, "", &cats) == -1)
  220. G_warning(_("Category file for <%s> not available"), map_name);
  221. Rast_set_c_null_value(&null_cell, 1);
  222. if (D_open_driver() != 0)
  223. G_fatal_error(_("No graphics device selected"));
  224. white = D_translate_color(DEFAULT_FG_COLOR);
  225. black = D_translate_color(DEFAULT_BG_COLOR);
  226. /* Figure out where to put text */
  227. D_setup_unity(0);
  228. D_get_src(&t, &b, &l, &r);
  229. if (opt7->answer != NULL) {
  230. sscanf(opt7->answers[0], "%lf", &Y1);
  231. sscanf(opt7->answers[1], "%lf", &Y0);
  232. sscanf(opt7->answers[2], "%lf", &X0);
  233. sscanf(opt7->answers[3], "%lf", &X1);
  234. }
  235. else { /* default */
  236. Y1 = 12;
  237. Y0 = 88;
  238. X0 = 3;
  239. X1 = 7;
  240. }
  241. x0 = l + (int)((r - l) * X0 / 100.);
  242. x1 = l + (int)((r - l) * X1 / 100.);
  243. y0 = t + (int)((b - t) * (100. - Y0) / 100.); /* make lower left the origin */
  244. y1 = t + (int)((b - t) * (100. - Y1) / 100.);
  245. if (y0 > y1) { /* allow for variety in order of corner */
  246. flip = !flip; /* selection without broken output */
  247. xyTemp = y0;
  248. y0 = y1;
  249. y1 = xyTemp;
  250. }
  251. if (x0 > x1) {
  252. xyTemp = x0;
  253. x0 = x1;
  254. x1 = xyTemp;
  255. }
  256. if (x0 == x1)
  257. x1++; /* avoid 0 width boxes */
  258. if (y0 == y1)
  259. y1++;
  260. if ((x0 < l) || (x1 > r) || (y0 < t) || (y1 > b)) /* for mouse or at= 0- or 100+; needs to be after order check */
  261. G_warning(_("Legend box lies outside of frame. Text may not display properly."));
  262. horiz = (x1 - x0 > y1 - y0);
  263. if (horiz)
  264. G_message(_("Drawing horizontal legend as box width exceeds height"));
  265. if (!fp && horiz) /* better than nothing */
  266. do_smooth = TRUE;
  267. MaxLabelLen = 0; /* init variable */
  268. /* How many categories to show */
  269. if (!fp) {
  270. if (Rast_read_range(map_name, "", &range) == -1)
  271. G_fatal_error(_("Range information for <%s> not available (run r.support)"),
  272. map_name);
  273. Rast_get_range_min_max(&range, &min_ind, &max_ind);
  274. if (Rast_is_c_null_value(&min_ind))
  275. G_fatal_error(_("Input map contains no data"));
  276. Rast_get_c_color_range(&min_colr, &max_colr, &colors);
  277. if (UserRange) {
  278. if (min_ind < UserRangeMin)
  279. min_ind = (int)ceil(UserRangeMin);
  280. if (max_ind > UserRangeMax)
  281. max_ind = (int)floor(UserRangeMax);
  282. if (min_ind > UserRangeMin) {
  283. min_ind =
  284. UserRangeMin <
  285. min_colr ? min_colr : (int)ceil(UserRangeMin);
  286. G_warning(_("Color range exceeds lower limit of actual data"));
  287. }
  288. if (max_ind < UserRangeMax) {
  289. max_ind =
  290. UserRangeMax >
  291. max_colr ? max_colr : (int)floor(UserRangeMax);
  292. G_warning(_("Color range exceeds upper limit of actual data"));
  293. }
  294. }
  295. /* cats_num is total number of categories in raster */
  296. /* do_cats is total number of categories to be displayed */
  297. /* k is number of cats to be displayed after skipping unlabeled cats */
  298. /* lines is number of text lines/legend window */
  299. cats_num = max_ind - min_ind + 1;
  300. if (lines == 0)
  301. lines = cats_num;
  302. do_cats = cats_num > lines ? lines : cats_num;
  303. if (do_cats == cats_num)
  304. lines = (int)ceil((1.0 * lines) / thin);
  305. if (!use_catlist) {
  306. catlist = (double *)G_calloc(lines + 1, sizeof(double));
  307. catlistCount = lines;
  308. }
  309. /* see how many boxes there REALLY will be */
  310. maxCat = 0.0;
  311. for (i = min_ind, j = 1, k = 0; j <= do_cats && i <= max_ind;
  312. j++, i += thin) {
  313. if (!flip)
  314. cstr = Rast_get_c_cat(&i, &cats);
  315. else {
  316. CELL cat = max_ind - (i - min_ind);
  317. cstr = Rast_get_c_cat(&cat, &cats);
  318. }
  319. if (!use_catlist)
  320. catlist[j - 1] = (double)i;
  321. if (!cstr[0]) { /* no cat label found, skip str output */
  322. if (hide_nodata)
  323. continue;
  324. }
  325. else { /* ie has a label */
  326. if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
  327. MaxLabelLen = strlen(cstr);
  328. }
  329. if (!hide_catnum)
  330. if (i > maxCat)
  331. maxCat = (double)i;
  332. k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
  333. }
  334. lines = k;
  335. /* figure out how long the category + label will be */
  336. if (use_catlist) {
  337. MaxLabelLen = 0;
  338. maxCat = 0; /* reset */
  339. for (i = 0, k = 0; i < catlistCount; i++) {
  340. if ((catlist[i] < min_ind) || (catlist[i] > max_ind)) {
  341. G_fatal_error(_("use=%s out of range [%d,%d] (extend with range= ?)"),
  342. opt8->answers[i], min_ind, max_ind);
  343. }
  344. cstr = Rast_get_d_cat(&catlist[i], &cats);
  345. if (!cstr[0]) { /* no cat label found, skip str output */
  346. if (hide_nodata)
  347. continue;
  348. }
  349. else { /* ie has a label */
  350. if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
  351. MaxLabelLen = strlen(cstr);
  352. }
  353. if (!hide_catnum)
  354. if (catlist[i] > maxCat)
  355. maxCat = catlist[i];
  356. k++;
  357. }
  358. if (0 == k) /* nothing to draw */
  359. lines = 0;
  360. }
  361. if (MaxLabelLen > 0) { /* ie we've picked up at least one label */
  362. MaxLabelLen++; /* compensate for leading space */
  363. if (!hide_catnum)
  364. MaxLabelLen += 3; /* compensate for "%2d) " */
  365. }
  366. else {
  367. if (!hide_catnum)
  368. MaxLabelLen = 1;
  369. }
  370. /* compensate for categories >100 */
  371. if (!hide_catnum) {
  372. if (maxCat > 99)
  373. MaxLabelLen += (int)(log10(maxCat));
  374. }
  375. /* following covers both the above if(do_cats == cats_num) and k++ loop */
  376. if (lines < 1) {
  377. lines = 1; /* ward off the dpl floating point exception */
  378. G_fatal_error(_("Nothing to draw! (no categories with labels? out of range?)"));
  379. }
  380. /* Figure number of lines, number of pixles per line and text size */
  381. dots_per_line = ((y1 - y0) / lines);
  382. /* switch to a smooth legend for CELL maps with too many cats */
  383. /* an alternate solution is to set dots_per_line=1 */
  384. if ((dots_per_line == 0) && (do_smooth == 0)) {
  385. if (!use_catlist) {
  386. G_message(_("Forcing a smooth legend: too many categories for current window height"));
  387. do_smooth = 1;
  388. }
  389. }
  390. /* center really tiny legends */
  391. if (opt7->answer == NULL) { /* if defualt scaling */
  392. if (!do_smooth && (dots_per_line < 4)) /* if so small that there's no box */
  393. if ((b - (dots_per_line * lines)) / (b * 1.0) > 0.15) /* if there's more than a 15% blank at the bottom */
  394. y0 = ((b - t) - (dots_per_line * lines)) / 2;
  395. }
  396. /* D_text_size((int)(dots_per_line*4/5), (int)(dots_per_line*4/5)) ; redundant */
  397. /* if(Rast_is_c_null_value(&min_ind) && Rast_is_c_null_value(&max_ind))
  398. {
  399. min_ind = 1;
  400. max_ind = 0;
  401. } */
  402. if (horiz)
  403. sprintf(DispFormat, "%%d");
  404. else {
  405. if (maxCat > 0.0)
  406. sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
  407. else
  408. sprintf(DispFormat, "%%2d");
  409. }
  410. }
  411. else { /* is fp */
  412. if (Rast_read_fp_range(map_name, "", &fprange) == -1)
  413. G_fatal_error(_("Range information for <%s> not available"),
  414. map_name);
  415. Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
  416. Rast_get_d_color_range(&min_dcolr, &max_dcolr, &colors);
  417. if (UserRange) {
  418. if (dmin < UserRangeMin)
  419. dmin = UserRangeMin;
  420. if (dmax > UserRangeMax)
  421. dmax = UserRangeMax;
  422. if (dmin > UserRangeMin) {
  423. dmin = UserRangeMin < min_dcolr ? min_dcolr : UserRangeMin;
  424. G_warning(_("Color range exceeds lower limit of actual data"));
  425. }
  426. if (dmax < UserRangeMax) {
  427. dmax = UserRangeMax > max_dcolr ? max_dcolr : UserRangeMax;
  428. G_warning(_("Color range exceeds upper limit of actual data"));
  429. }
  430. }
  431. if (use_catlist) {
  432. for (i = 0; i < catlistCount; i++) {
  433. if ((catlist[i] < dmin) || (catlist[i] > dmax)) {
  434. G_fatal_error(_("use=%s out of range [%.3f, %.3f] (extend with range= ?)"),
  435. opt8->answers[i], dmin, dmax);
  436. }
  437. if (strlen(opt8->answers[i]) > MaxLabelLen)
  438. MaxLabelLen = strlen(opt8->answers[i]);
  439. }
  440. }
  441. do_cats = 0; /* if only to get rid of the compiler warning */
  442. cats_num = 0; /* if only to get rid of the compiler warning */
  443. /* determine how many significant digits to display based on range */
  444. if (0 == (dmax - dmin)) /* trap divide by 0 for single value rasters */
  445. sprintf(DispFormat, "%%f");
  446. else {
  447. SigDigits = (int)ceil(log10(fabs(25 / (dmax - dmin))));
  448. if (SigDigits < 0)
  449. SigDigits = 0;
  450. if (SigDigits < 7)
  451. sprintf(DispFormat, "%%.%df", SigDigits);
  452. else
  453. sprintf(DispFormat, "%%.2g"); /* eg 4.2e-9 */
  454. }
  455. }
  456. if (use_catlist) {
  457. cats_num = catlistCount;
  458. do_cats = catlistCount;
  459. lines = catlistCount;
  460. do_smooth = 0;
  461. }
  462. if (do_smooth) {
  463. int wleg, lleg, dx, dy;
  464. int txsiz;
  465. int ppl;
  466. int tcell;
  467. float ScaleFactor = 1.0;
  468. if (horiz) {
  469. lleg = x1 - x0;
  470. dx = 0;
  471. dy = y1 - y0;
  472. if (fp)
  473. flip = !flip; /* horiz floats look better not flipped by default */
  474. }
  475. else {
  476. lleg = y1 - y0;
  477. dy = 0;
  478. dx = x1 - x0;
  479. }
  480. /* Draw colors */
  481. for (k = 0; k < lleg; k++) {
  482. if (!fp) {
  483. if (!flip)
  484. tcell =
  485. min_ind + k * (double)(1 + max_ind - min_ind) / lleg;
  486. else
  487. tcell =
  488. (max_ind + 1) - k * (double)(1 + max_ind -
  489. min_ind) / lleg;
  490. D_color((CELL) tcell, &colors);
  491. }
  492. else {
  493. if (!flip)
  494. val = dmin + k * (dmax - dmin) / lleg;
  495. else
  496. val = dmax - k * (dmax - dmin) / lleg;
  497. D_d_color(val, &colors);
  498. }
  499. if (dx < dy)
  500. D_box_abs(x0 + k, y0, x0 + k + (dx ? -dx : 1),
  501. y0 - (dy ? -dy : 1));
  502. else
  503. D_box_abs(x0, y0 + k, x0 - (dx ? -dx : 1),
  504. y0 + k + (dy ? -dy : 1));
  505. }
  506. /* Format text */
  507. if (!fp) { /* cut down labelnum so they don't repeat */
  508. if (do_cats < steps)
  509. steps = do_cats;
  510. if (1 == steps)
  511. steps = 2; /* ward off the ppl floating point exception */
  512. }
  513. for (k = 0; k < steps; k++) {
  514. if (!fp) {
  515. if (!flip)
  516. tcell =
  517. min_ind + k * (double)(max_ind - min_ind) / (steps -
  518. 1);
  519. else
  520. tcell =
  521. max_ind - k * (double)(max_ind - min_ind) / (steps -
  522. 1);
  523. cstr = Rast_get_c_cat(&tcell, &cats);
  524. if (!cstr[0]) /* no cats found, disable str output */
  525. hide_catstr = 1;
  526. else
  527. hide_catstr = hidestr->answer;
  528. buff[0] = 0; /* blank string */
  529. if (!hide_catnum) { /* num */
  530. sprintf(buff, DispFormat, tcell);
  531. if (!hide_catstr) /* both */
  532. strcat(buff, ")");
  533. }
  534. if (!hide_catstr) /* str */
  535. sprintf(buff + strlen(buff), " %s", cstr);
  536. }
  537. else { /* ie FP map */
  538. if (hide_catnum)
  539. buff[0] = 0; /* no text */
  540. else {
  541. if (!flip)
  542. val = dmin + k * (dmax - dmin) / (steps - 1);
  543. else
  544. val = dmax - k * (dmax - dmin) / (steps - 1);
  545. sprintf(buff, DispFormat, val);
  546. }
  547. }
  548. /* this probably shouldn't happen mid-loop as text sizes
  549. might not end up being uniform, but it's a start */
  550. if (strlen(buff) > MaxLabelLen)
  551. MaxLabelLen = strlen(buff);
  552. /* Draw text */
  553. if (!horiz)
  554. txsiz = (int)((y1 - y0) / 20);
  555. else
  556. txsiz = (int)((x1 - x0) / 20);
  557. /* scale text to fit in window if position not manually set */
  558. /* usually not needed, except when frame is really narrow */
  559. if (opt7->answer == NULL) { /* ie defualt scaling */
  560. ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
  561. if (ScaleFactor < 1.0) {
  562. txsiz = (int)(txsiz * ScaleFactor);
  563. }
  564. }
  565. if (txsiz < 0)
  566. txsiz = 0; /* keep it sane */
  567. D_text_size(txsiz, txsiz);
  568. D_use_color(color);
  569. ppl = (lleg) / (steps - 1);
  570. if (!horiz) {
  571. if (!k) /* first */
  572. D_pos_abs(x1 + 4, y0 + txsiz);
  573. else if (k == steps - 1) /* last */
  574. D_pos_abs(x1 + 4, y1);
  575. else
  576. D_pos_abs(x1 + 4, y0 + ppl * k + txsiz / 2);
  577. }
  578. else {
  579. /* text width is 0.81 of text height? so even though we set width
  580. to txsiz with D_text_size(), we still have to reduce.. hmmm */
  581. if (!k) /* first */
  582. D_pos_abs(x0 - (strlen(buff) * txsiz * .81 / 2),
  583. y1 + 4 + txsiz);
  584. else if (k == steps - 1) /* last */
  585. D_pos_abs(x1 - (strlen(buff) * txsiz * .81 / 2),
  586. y1 + 4 + txsiz);
  587. else
  588. D_pos_abs(x0 + ppl * k -
  589. (strlen(buff) * txsiz * .81 / 2),
  590. y1 + 4 + txsiz);
  591. }
  592. D_text(buff);
  593. } /*for */
  594. lleg = y1 - y0;
  595. wleg = x1 - x0;
  596. /* Black box */
  597. D_use_color(black);
  598. D_begin();
  599. D_move_abs(x0 + 1, y0 + 1);
  600. D_cont_rel(0, lleg - 2);
  601. D_cont_rel(wleg - 2, 0);
  602. D_cont_rel(0, 2 - lleg);
  603. D_close();
  604. D_end();
  605. D_stroke();
  606. /* White box */
  607. D_use_color(white);
  608. D_begin();
  609. D_move_abs(x0, y0);
  610. D_cont_rel(0, lleg);
  611. D_cont_rel(wleg, 0);
  612. D_cont_rel(0, -lleg);
  613. D_close();
  614. D_end();
  615. D_stroke();
  616. }
  617. else { /* non FP, no smoothing */
  618. int txsiz, true_l, true_r;
  619. float ScaleFactor = 1.0;
  620. /* set legend box bounds */
  621. true_l = l;
  622. true_r = r; /* preserve window width */
  623. l = x0;
  624. t = y0;
  625. r = x1;
  626. b = y1;
  627. D_pos_abs(x0, y0);
  628. /* figure out box height */
  629. if (do_cats == cats_num)
  630. dots_per_line = (b - t) / (lines + 1); /* +1 line for the two 1/2s at top and bottom */
  631. else
  632. dots_per_line = (b - t) / (lines + 2); /* + another line for 'x of y categories' text */
  633. /* adjust text size */
  634. /* txsiz = (int)((y1-y0)/(1.5*(lines+5))); */
  635. txsiz = (int)((y1 - y0) / (2.0 * lines));
  636. /* scale text to fit in window if position not manually set */
  637. if (opt7->answer == NULL) { /* ie defualt scaling */
  638. ScaleFactor = ((true_r - true_l) / ((MaxLabelLen + 3) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
  639. if (ScaleFactor < 1.0) {
  640. txsiz = (int)floor(txsiz * ScaleFactor);
  641. dots_per_line = (int)floor(dots_per_line * ScaleFactor);
  642. }
  643. }
  644. if (dots_per_line < txsiz)
  645. txsiz = dots_per_line;
  646. D_text_size(txsiz, txsiz);
  647. /* Set up box arrays */
  648. x_box[0] = 0;
  649. y_box[0] = 0;
  650. x_box[1] = 0;
  651. y_box[1] = (5 - dots_per_line);
  652. x_box[2] = (dots_per_line - 5);
  653. y_box[2] = 0;
  654. x_box[3] = 0;
  655. y_box[3] = (dots_per_line - 5);
  656. x_box[4] = (5 - dots_per_line);
  657. y_box[4] = 0;
  658. /* Draw away */
  659. /* if(ScaleFactor < 1.0) */
  660. /* cur_dot_row = ((b-t) - (dots_per_line*lines))/2; *//* this will center the legend */
  661. /* else */
  662. cur_dot_row = t + dots_per_line / 2;
  663. /* j = (do_cats == cats_num ? 1 : 2 ); */
  664. for (i = 0, k = 0; i < catlistCount; i++)
  665. /* for(i=min_ind, j=1, k=0; j<=do_cats && i<=max_ind; j++, i+=thin) */
  666. {
  667. if (!flip)
  668. cstr = Rast_get_d_cat(&catlist[i], &cats);
  669. else
  670. cstr = Rast_get_d_cat(&catlist[catlistCount - i - 1], &cats);
  671. if (!cstr[0]) { /* no cat label found, skip str output */
  672. hide_catstr = 1;
  673. if (hide_nodata)
  674. continue;
  675. }
  676. else
  677. hide_catstr = hidestr->answer;
  678. k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
  679. /* White box */
  680. cur_dot_row += dots_per_line;
  681. D_use_color(white);
  682. D_begin();
  683. D_move_abs(l + 2, (cur_dot_row - 1));
  684. D_cont_rel(0, (3 - dots_per_line));
  685. D_cont_rel((dots_per_line - 3), 0);
  686. D_cont_rel(0, (dots_per_line - 3));
  687. D_close();
  688. D_end();
  689. D_stroke();
  690. /* Black box */
  691. D_use_color(black);
  692. D_begin();
  693. D_move_abs(l + 3, (cur_dot_row - 2));
  694. D_cont_rel(0, (5 - dots_per_line));
  695. D_cont_rel((dots_per_line - 5), 0);
  696. D_cont_rel(0, (dots_per_line - 5));
  697. D_close();
  698. D_end();
  699. D_stroke();
  700. /* Color solid box */
  701. if (!fp) {
  702. if (!flip)
  703. D_color((CELL) (int)catlist[i], &colors);
  704. else
  705. D_color((CELL) (int)catlist[catlistCount - i - 1],
  706. &colors);
  707. }
  708. else {
  709. if (!flip)
  710. D_d_color(catlist[i], &colors);
  711. else
  712. D_d_color(catlist[catlistCount - i - 1], &colors);
  713. }
  714. D_pos_abs(l + 3, (cur_dot_row - 2));
  715. D_polygon_rel(x_box, y_box, 5);
  716. /* Draw text */
  717. D_use_color(color);
  718. if (!fp) {
  719. /* nothing, box only */
  720. buff[0] = 0;
  721. if (!hide_catnum) { /* num */
  722. sprintf(buff, DispFormat, (int)catlist[i]);
  723. if (!flip)
  724. sprintf(buff, DispFormat, (int)catlist[i]);
  725. else
  726. sprintf(buff, DispFormat,
  727. (int)catlist[catlistCount - i - 1]);
  728. if (!hide_catstr) /* both */
  729. strcat(buff, ")");
  730. }
  731. if (!hide_catstr) /* str */
  732. sprintf(buff + strlen(buff), " %s", cstr);
  733. }
  734. else { /* is fp */
  735. if (!flip)
  736. sprintf(buff, DispFormat, catlist[i]);
  737. else
  738. sprintf(buff, DispFormat, catlist[catlistCount - i - 1]);
  739. }
  740. D_pos_abs((l + 3 + dots_per_line), (cur_dot_row) - 3);
  741. D_text(buff);
  742. }
  743. if (0 == k)
  744. G_fatal_error(_("Nothing to draw! (no categories with labels?)")); /* "(..., out of range?)" */
  745. if (do_cats != cats_num) {
  746. cur_dot_row += dots_per_line;
  747. /* sprintf(buff, "%d of %d categories\n", (j-1), cats_num) ; */
  748. sprintf(buff, "%d of %d categories\n", k, cats_num);
  749. /* shrink text if it will run off the screen */
  750. MaxLabelLen = strlen(buff) + 4;
  751. ScaleFactor = ((true_r - true_l) / (MaxLabelLen * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
  752. if (ScaleFactor < 1.0) {
  753. txsiz = (int)floor(txsiz * ScaleFactor);
  754. D_text_size(txsiz, txsiz);
  755. }
  756. D_use_color(white);
  757. D_pos_abs((l + 3 + dots_per_line), (cur_dot_row));
  758. D_text(buff);
  759. }
  760. }
  761. D_close_driver();
  762. exit(EXIT_SUCCESS);
  763. }