cats.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329
  1. /*!
  2. * \file lib/raster/cats.c
  3. *
  4. * \brief Raster Library - Raster categories management
  5. *
  6. * Code in this file works with category files. There are two formats:
  7. * Pre 3.0 direct category encoding form:
  8. *
  9. * 2 categories
  10. * Map Title
  11. * Elevation: 1000.00 to 1005.00 feet
  12. * Elevation: 1005.00 to 1010.00 feet
  13. * Elevation: 1010.00 to 1015.00 feet
  14. *
  15. * 3.0 format
  16. *
  17. * # 2 categories
  18. * Map Title
  19. * Elevation: $1.2 to $2.2 feet ## Format Statement
  20. * 5.0 1000 5.0 1005 ## Coefficients
  21. *
  22. * The coefficient line can be followed by explicit category labels
  23. * which override the format label generation.
  24. * 0:no data
  25. * 2: .
  26. * 5: . ## explicit category labels
  27. * 7: .
  28. * explicit labels can be also of the form:
  29. * 5.5:5:9 label description
  30. * or
  31. * 15:30 label description
  32. *
  33. * In the format line
  34. * $1 refers to the value num*5.0+1000 (ie, using the first 2 coefficients)
  35. * $2 refers to the value num*5.0+1005 (ie, using the last 2 coefficients)
  36. *
  37. * $1.2 will print $1 with 2 decimal places.
  38. *
  39. * Also, the form $?xxx$yyy$ translates into yyy if the category is 1, xxx
  40. * otherwise. The $yyy$ is optional. Thus
  41. *
  42. * $1 meter$?s
  43. *
  44. * will become: 1 meter (for category 1)
  45. * 2 meters (for category 2), etc.
  46. *
  47. * The format and coefficients above would be used to generate the
  48. * following statement in creation of the format appropriate category
  49. * string for category "num":
  50. *
  51. * sprintf(buff,"Elevation: %.2f to %.2f feet", num*5.0+1000, num*5.0*1005)
  52. *
  53. * Note: while both the format and coefficient lines must be present
  54. * a blank line for the fmt will effectively suppress automatic
  55. * label generation
  56. *
  57. * Note: quant rules of Categories structures are heavily dependent
  58. * on the fact that rules are stored in the same order they are entered.
  59. * since i-th rule and i-th label are entered at the same time, we
  60. * know that i-th rule maps fp range to i, thus we know for sure
  61. * that cats.labels[i] corresponds to i-th quant rule
  62. *
  63. * (C) 2001-2009 by the GRASS Development Team
  64. *
  65. * This program is free software under the GNU General Public License
  66. * (>=v2). Read the file COPYING that comes with GRASS for details.
  67. *
  68. * \author Original author CERL
  69. */
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include <grass/gis.h>
  73. #include <grass/raster.h>
  74. #include <grass/glocale.h>
  75. static void get_cond(char **, char *, DCELL);
  76. static int get_fmt(char **, char *, int *);
  77. static int cmp(const void *, const void *);
  78. static void write_cats(const char *element, const char *name,
  79. struct Categories *cats);
  80. static CELL read_cats(const char *element, const char *name,
  81. const char *mapset, struct Categories *pcats, int full);
  82. static struct Categories save_cats;
  83. /*!
  84. * \brief Read raster category file
  85. *
  86. * The category file for raster map <i>name</i> in <i>mapset</i> is
  87. * read into the <i>cats</i> structure. If there is an error reading
  88. * the category file, a diagnostic message is printed and -1 is
  89. * returned. Otherwise, 0 is returned.
  90. *
  91. * \param name raster map name
  92. * \param mapset mapset name
  93. * \param[out] pcats pointer to Cats structure
  94. *
  95. * \return -1 on error
  96. * \return 0 on success
  97. */
  98. int Rast_read_cats(const char *name,
  99. const char *mapset, struct Categories *pcats)
  100. {
  101. switch (read_cats("cats", name, mapset, pcats, 1)) {
  102. case -2:
  103. G_warning(_("Category support for <%s@%s> missing"), name, mapset);
  104. break;
  105. case -1:
  106. G_warning(_("Category support for <%s@%s> invalid"), name, mapset);
  107. break;
  108. default:
  109. return 0;
  110. }
  111. return -1;
  112. }
  113. /*!
  114. * \brief Read vector category file
  115. *
  116. * <b>Note:</b> This function works with <b>old</b> vector format.
  117. *
  118. * \todo: To be moved to the vector library
  119. *
  120. * The category file for vector map <i>name</i> in <i>mapset</i> is
  121. * read into the <i>cats</i> structure. If there is an error reading
  122. * the category file, a diagnostic message is printed and -1 is
  123. * returned. Otherwise, 0 is returned.
  124. *
  125. * \param name vector map name
  126. * \param mapset mapset name
  127. * \param[out] pcats pointer to Cats structure
  128. *
  129. * \return -1 on error
  130. * \return 0 on success
  131. */
  132. int Rast_read_vector_cats(const char *name,
  133. const char *mapset, struct Categories *pcats)
  134. {
  135. switch (read_cats("dig_cats", name, mapset, pcats, 1)) {
  136. case -2:
  137. G_warning(_("Category support for vector map <%s@%s> missing"),
  138. name, mapset);
  139. break;
  140. case -1:
  141. G_warning(_("Category support for vector map <%s@%s> invalid"),
  142. name, mapset);
  143. break;
  144. default:
  145. return 0;
  146. }
  147. return -1;
  148. }
  149. /*!
  150. \brief Get the max category number
  151. Return the max category number of a raster map
  152. of type CELL.
  153. \param name raster map name
  154. \param mapset mapset name
  155. \return -1 on error
  156. \return number of cats
  157. */
  158. CELL Rast_get_max_c_cat(const char *name, const char *mapset)
  159. {
  160. struct Range range;
  161. CELL min, max;
  162. /* return the max category number */
  163. if (Rast_read_range(name, mapset, &range) < 0)
  164. return -1;
  165. Rast_get_range_min_max(&range, &min, &max);
  166. if (Rast_is_c_null_value(&max))
  167. max = 0;
  168. return max;
  169. }
  170. static CELL read_cats(const char *element,
  171. const char *name,
  172. const char *mapset, struct Categories *pcats, int full)
  173. {
  174. FILE *fd;
  175. char buff[1024];
  176. CELL cat1, cat2;
  177. DCELL val1, val2;
  178. int old = 0, fp_map;
  179. long num = -1;
  180. if (strncmp(element, "dig", 3) == 0)
  181. fp_map = 0;
  182. else
  183. fp_map = Rast_map_is_fp(name, mapset);
  184. if (!(fd = G_fopen_old(element, name, mapset)))
  185. return -2;
  186. /* Read the number of categories */
  187. if (G_getl(buff, sizeof buff, fd) == 0)
  188. goto error;
  189. if (sscanf(buff, "# %ld", &num) == 1)
  190. old = 0;
  191. else if (sscanf(buff, "%ld", &num) == 1)
  192. old = 1;
  193. if (!full) {
  194. fclose(fd);
  195. if (num < 0)
  196. return 0; /* coorect */
  197. return (CELL) num;
  198. }
  199. /* Read the title for the file */
  200. if (G_getl(buff, sizeof buff, fd) == 0)
  201. goto error;
  202. G_strip(buff);
  203. /* G_ascii_check(buff) ; */
  204. Rast_init_cats(buff, pcats);
  205. if (num >= 0)
  206. pcats->num = num;
  207. if (!old) {
  208. char fmt[256];
  209. float m1, a1, m2, a2;
  210. if (G_getl(fmt, sizeof fmt, fd) == 0)
  211. goto error;
  212. /* next line contains equation coefficients */
  213. if (G_getl(buff, sizeof buff, fd) == 0)
  214. goto error;
  215. if (sscanf(buff, "%f %f %f %f", &m1, &a1, &m2, &a2) != 4)
  216. goto error;
  217. Rast_set_cats_fmt(fmt, m1, a1, m2, a2, pcats);
  218. }
  219. /* Read all category names */
  220. for (cat1 = 0;; cat1++) {
  221. char label[1024];
  222. if (G_getl(buff, sizeof buff, fd) == 0)
  223. break;
  224. if (old)
  225. Rast_set_c_cat(&cat1, &cat1, buff, pcats);
  226. else {
  227. *label = 0;
  228. if (sscanf(buff, "%1s", label) != 1)
  229. continue;
  230. if (*label == '#')
  231. continue;
  232. *label = 0;
  233. /* for fp maps try to read a range of data */
  234. if (fp_map
  235. && sscanf(buff, "%lf:%lf:%[^\n]", &val1, &val2, label) == 3)
  236. Rast_set_cat(&val1, &val2, label, pcats, DCELL_TYPE);
  237. else if (!fp_map
  238. && sscanf(buff, "%d:%d:%[^\n]", &cat1, &cat2, label) == 3)
  239. Rast_set_cat(&cat1, &cat2, label, pcats, CELL_TYPE);
  240. else if (sscanf(buff, "%d:%[^\n]", &cat1, label) >= 1)
  241. Rast_set_cat(&cat1, &cat1, label, pcats, CELL_TYPE);
  242. else if (sscanf(buff, "%lf:%[^\n]", &val1, label) >= 1)
  243. Rast_set_cat(&val1, &val1, label, pcats, DCELL_TYPE);
  244. else
  245. goto error;
  246. }
  247. }
  248. fclose(fd);
  249. return 0;
  250. error:
  251. fclose(fd);
  252. return -1;
  253. }
  254. /*!
  255. * \brief Get title from category structure struct
  256. *
  257. * \todo Remove from GIS Library, replace by Rast_get_c_cats_title().
  258. *
  259. * Map layers store a one-line title in the category structure as
  260. * well. This routine returns a pointer to the title contained in the
  261. * <i>cats</i> structure. A legal pointer is always returned. If the
  262. * map layer does not have a title, then a pointer to the empty string
  263. * "" is returned.
  264. *
  265. * \param pcats pointer to Categories structure
  266. *
  267. * \return title
  268. * \return "" if missing
  269. */
  270. char *Rast_get_cats_title(const struct Categories *pcats)
  271. {
  272. return pcats->title ? pcats->title : "";
  273. }
  274. /*!
  275. * \brief Get a raster category label (CELL)
  276. *
  277. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  278. * structure and returns a pointer to a string which is the label for
  279. * the category. A legal pointer is always returned. If the category
  280. * does not exist in <i>pcats</i>, then a pointer to the empty string
  281. * "" is returned.
  282. *
  283. * <b>Warning:</b> The pointer that is returned points to a hidden
  284. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  285. * buffer.
  286. *
  287. * \param rast cell value
  288. * \param pcats pointer to Categories structure
  289. *
  290. * \return pointer to category label
  291. * \return "" if category is not found
  292. */
  293. char *Rast_get_c_cat(CELL * rast, struct Categories *pcats)
  294. {
  295. return Rast_get_cat(rast, pcats, CELL_TYPE);
  296. }
  297. /*!
  298. * \brief Get a raster category label (FCELL)
  299. *
  300. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  301. * structure and returns a pointer to a string which is the label for
  302. * the category. A legal pointer is always returned. If the category
  303. * does not exist in <i>pcats</i>, then a pointer to the empty string
  304. * "" is returned.
  305. *
  306. * <b>Warning:</b> The pointer that is returned points to a hidden
  307. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  308. * buffer.
  309. *
  310. * \param rast cell value
  311. * \param pcats pointer to Categories structure
  312. *
  313. * \return pointer to category label
  314. * \return "" if category is not found
  315. */
  316. char *Rast_get_f_cat(FCELL * rast, struct Categories *pcats)
  317. {
  318. return Rast_get_cat(rast, pcats, FCELL_TYPE);
  319. }
  320. /*!
  321. * \brief Get a raster category label (DCELL)
  322. *
  323. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  324. * structure and returns a pointer to a string which is the label for
  325. * the category. A legal pointer is always returned. If the category
  326. * does not exist in <i>pcats</i>, then a pointer to the empty string
  327. * "" is returned.
  328. *
  329. * <b>Warning:</b> The pointer that is returned points to a hidden
  330. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  331. * buffer.
  332. *
  333. * \param rast cell value
  334. * \param pcats pointer to Categories structure
  335. *
  336. * \return pointer to category label
  337. * \return "" if category is not found
  338. */
  339. char *Rast_get_d_cat(DCELL * rast, struct Categories *pcats)
  340. {
  341. return Rast_get_cat(rast, pcats, DCELL_TYPE);
  342. }
  343. /*!
  344. * \brief Get a raster category label
  345. *
  346. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  347. * structure and returns a pointer to a string which is the label for
  348. * the category. A legal pointer is always returned. If the category
  349. * does not exist in <i>pcats</i>, then a pointer to the empty string
  350. * "" is returned.
  351. *
  352. * <b>Warning:</b> The pointer that is returned points to a hidden
  353. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  354. * buffer.
  355. *
  356. * \param rast cell value
  357. * \param pcats pointer to Categories structure
  358. * \param data_type map type (CELL, FCELL, DCELL)
  359. *
  360. * \return pointer to category label
  361. * \return "" if category is not found
  362. */
  363. char *Rast_get_cat(void *rast,
  364. struct Categories *pcats, RASTER_MAP_TYPE data_type)
  365. {
  366. static char label[1024];
  367. char *f, *l, *v;
  368. CELL i;
  369. DCELL val;
  370. float a[2];
  371. char fmt[30], value_str[30];
  372. if (Rast_is_null_value(rast, data_type)) {
  373. sprintf(label, "no data");
  374. return label;
  375. }
  376. /* first search the list of labels */
  377. *label = 0;
  378. val = Rast_get_d_value(rast, data_type);
  379. i = Rast_quant_get_cell_value(&pcats->q, val);
  380. G_debug(5, "Rast_get_cat(): val %lf found i %d", val, i);
  381. if (!Rast_is_c_null_value(&i) && i < pcats->ncats) {
  382. if (pcats->labels[i] != NULL)
  383. return pcats->labels[i];
  384. return label;
  385. }
  386. /* generate the label */
  387. if ((f = pcats->fmt) == NULL)
  388. return label;
  389. a[0] = (float)val *pcats->m1 + pcats->a1;
  390. a[1] = (float)val *pcats->m2 + pcats->a2;
  391. l = label;
  392. while (*f) {
  393. if (*f == '$') {
  394. f++;
  395. if (*f == '$')
  396. *l++ = *f++;
  397. else if (*f == '?') {
  398. f++;
  399. get_cond(&f, v = value_str, val);
  400. while (*v)
  401. *l++ = *v++;
  402. }
  403. else if (get_fmt(&f, fmt, &i)) {
  404. sprintf(v = value_str, fmt, a[i]);
  405. while (*v)
  406. *l++ = *v++;
  407. }
  408. else
  409. *l++ = '$';
  410. }
  411. else {
  412. *l++ = *f++;
  413. }
  414. }
  415. *l = 0;
  416. return label;
  417. }
  418. /*!
  419. * \brief Sets marks for all categories to 0.
  420. *
  421. * This initializes Categories structure for subsequent calls to
  422. * Rast_mark_cats() for each row of data, where non-zero mark for
  423. * i-th label means that some of the cells in rast_row are labeled
  424. * with i-th label and fall into i-th data range. These marks help
  425. * determine from the Categories structure which labels were used and
  426. * which weren't.
  427. *
  428. * \param pcats pointer to Categories structure
  429. */
  430. void Rast_unmark_cats(struct Categories *pcats)
  431. {
  432. int i;
  433. for (i = 0; i < pcats->ncats; i++)
  434. pcats->marks[i] = 0;
  435. }
  436. /*!
  437. * \brief Looks up the category label for each raster value (CELL).
  438. *
  439. * Looks up the category label for each raster value in the
  440. * <i>rast_row</i> and updates the marks for labels found.
  441. *
  442. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  443. * raster cells read so far which are labeled with i-th label and fall
  444. * into i-th data range.
  445. *
  446. * \param rast_row raster row to update stats
  447. * \param ncols number of columns
  448. * \param pcats pointer to Categories structure
  449. *
  450. */
  451. void Rast_mark_c_cats(const CELL * rast_row,
  452. int ncols, struct Categories *pcats)
  453. {
  454. Rast_mark_cats(rast_row, ncols, pcats, CELL_TYPE);
  455. }
  456. /*!
  457. * \brief Looks up the category label for each raster value (FCELL).
  458. *
  459. * Looks up the category label for each raster value in the
  460. * <i>rast_row</i> and updates the marks for labels found.
  461. *
  462. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  463. * raster cells read so far which are labeled with i-th label and fall
  464. * into i-th data range.
  465. *
  466. * \param rast_row raster row to update stats
  467. * \param ncols number of columns
  468. * \param pcats pointer to Categories structure
  469. *
  470. */
  471. void Rast_mark_f_cats(const FCELL * rast_row,
  472. int ncols, struct Categories *pcats)
  473. {
  474. Rast_mark_cats(rast_row, ncols, pcats, FCELL_TYPE);
  475. }
  476. /*!
  477. * \brief Looks up the category label for each raster value (DCELL).
  478. *
  479. * Looks up the category label for each raster value in the
  480. * <i>rast_row</i> and updates the marks for labels found.
  481. *
  482. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  483. * raster cells read so far which are labeled with i-th label and fall
  484. * into i-th data range.
  485. *
  486. * \param rast_row raster row to update stats
  487. * \param ncols number of columns
  488. * \param pcats pointer to Categories structure
  489. *
  490. */
  491. void Rast_mark_d_cats(const DCELL * rast_row,
  492. int ncols, struct Categories *pcats)
  493. {
  494. Rast_mark_cats(rast_row, ncols, pcats, DCELL_TYPE);
  495. }
  496. /*!
  497. * \brief Looks up the category label for each raster value (DCELL).
  498. *
  499. * Looks up the category label for each raster value in the
  500. * <i>rast_row</i> and updates the marks for labels found.
  501. *
  502. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  503. * raster cells read so far which are labeled with i-th label and fall
  504. * into i-th data range.
  505. *
  506. * \param rast_row raster row to update stats
  507. * \param ncols number of columns
  508. * \param pcats pointer to Categories structure
  509. * \param data_type map type
  510. *
  511. * \return -1 on error
  512. * \return 1 on success
  513. */
  514. int Rast_mark_cats(const void *rast_row,
  515. int ncols, struct Categories *pcats,
  516. RASTER_MAP_TYPE data_type)
  517. {
  518. size_t size = Rast_cell_size(data_type);
  519. CELL i;
  520. while (ncols-- > 0) {
  521. i = Rast_quant_get_cell_value(&pcats->q,
  522. Rast_get_d_value(rast_row, data_type));
  523. if (Rast_is_c_null_value(&i))
  524. continue;
  525. if (i > pcats->ncats)
  526. return -1;
  527. pcats->marks[i]++;
  528. rast_row = G_incr_void_ptr(rast_row, size);
  529. }
  530. return 1;
  531. }
  532. /*!
  533. * \brief Rewind raster categories
  534. *
  535. * After call to this function Rast_get_next_marked_cat() returns
  536. * the first marked cat label.
  537. *
  538. * \param pcats pointer to Categories structure
  539. */
  540. void Rast_rewind_cats(struct Categories *pcats)
  541. {
  542. pcats->last_marked_rule = -1;
  543. }
  544. /*!
  545. \brief Get next marked raster categories (DCELL)
  546. \param pcats pointer to Categories structure
  547. \param rast1, rast2 cell values (raster range)
  548. \param[out] count count
  549. \return NULL if not found
  550. \return description if found
  551. */
  552. char *Rast_get_next_marked_d_cat(struct Categories *pcats,
  553. DCELL * rast1, DCELL * rast2, long *count)
  554. {
  555. char *descr = NULL;
  556. int found, i;
  557. found = 0;
  558. /* pcats->ncats should be == Rast_quant_nof_rules(&pcats->q) */
  559. G_debug(3, "last marked %d nrules %d\n", pcats->last_marked_rule,
  560. Rast_quant_nof_rules(&pcats->q));
  561. for (i = pcats->last_marked_rule + 1; i < Rast_quant_nof_rules(&pcats->q);
  562. i++) {
  563. descr = Rast_get_ith_d_cat(pcats, i, rast1, rast2);
  564. G_debug(5, "%d %d", i, pcats->marks[i]);
  565. if (pcats->marks[i]) {
  566. found = 1;
  567. break;
  568. }
  569. }
  570. if (!found)
  571. return NULL;
  572. *count = pcats->marks[i];
  573. pcats->last_marked_rule = i;
  574. return descr;
  575. }
  576. /*!
  577. \brief Get next marked raster categories (CELL)
  578. \param pcats pointer to Categories structure
  579. \param rast1, rast2 cell values (raster range)
  580. \param[out] count count
  581. \return NULL if not found
  582. \return description if found
  583. */
  584. char *Rast_get_next_marked_c_cat(struct Categories *pcats,
  585. CELL * rast1, CELL * rast2, long *count)
  586. {
  587. return Rast_get_next_marked_cat(pcats, rast1, rast2, count, CELL_TYPE);
  588. }
  589. /*!
  590. \brief Get next marked raster categories (FCELL)
  591. \param pcats pointer to Categories structure
  592. \param rast1, rast2 cell values (raster range)
  593. \param[out] count count
  594. \return NULL if not found
  595. \return description if found
  596. */
  597. char *Rast_get_next_marked_f_cat(struct Categories *pcats,
  598. FCELL * rast1, FCELL * rast2, long *count)
  599. {
  600. return Rast_get_next_marked_cat(pcats, rast1, rast2, count, FCELL_TYPE);
  601. }
  602. /*!
  603. \brief Get next marked raster categories
  604. \param pcats pointer to Categories structure
  605. \param rast1, rast2 cell values (raster range)
  606. \param[out] count count
  607. \param data_type map type
  608. \return NULL if not found
  609. \return description if found
  610. */
  611. char *Rast_get_next_marked_cat(struct Categories *pcats,
  612. void *rast1, void *rast2,
  613. long *count, RASTER_MAP_TYPE data_type)
  614. {
  615. DCELL val1, val2;
  616. char *lab;
  617. lab = Rast_get_next_marked_d_cat(pcats, &val1, &val2, count);
  618. Rast_set_d_value(rast1, val1, data_type);
  619. Rast_set_d_value(rast2, val2, data_type);
  620. return lab;
  621. }
  622. static int get_fmt(char **f, char *fmt, int *i)
  623. {
  624. char *ff;
  625. ff = *f;
  626. if (*ff == 0)
  627. return 0;
  628. if (*ff == '$') {
  629. *f = ff + 1;
  630. return 0;
  631. }
  632. switch (*ff++) {
  633. case '1':
  634. *i = 0;
  635. break;
  636. case '2':
  637. *i = 1;
  638. break;
  639. default:
  640. return 0;
  641. }
  642. *fmt++ = '%';
  643. *fmt++ = '.';
  644. if (*ff++ != '.') {
  645. *f = ff - 1;
  646. *fmt++ = '0';
  647. *fmt++ = 'f';
  648. *fmt = 0;
  649. return 1;
  650. }
  651. *fmt = '0';
  652. while (*ff >= '0' && *ff <= '9')
  653. *fmt++ = *ff++;
  654. *fmt++ = 'f';
  655. *fmt = 0;
  656. *f = ff;
  657. return 1;
  658. }
  659. static void get_cond(char **f, char *value, DCELL val)
  660. {
  661. char *ff;
  662. ff = *f;
  663. if (val == 1.) {
  664. while (*ff)
  665. if (*ff++ == '$')
  666. break;
  667. }
  668. while (*ff)
  669. if (*ff == '$') {
  670. ff++;
  671. break;
  672. }
  673. else
  674. *value++ = *ff++;
  675. if (val != 1.) {
  676. while (*ff)
  677. if (*ff++ == '$')
  678. break;
  679. }
  680. *value = 0;
  681. *f = ff;
  682. }
  683. /*!
  684. * \brief Set a raster category label (CELL)
  685. *
  686. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  687. * category structure <i>pcats</i>.
  688. *
  689. * \param rast1, rast2 raster values (range)
  690. * \param label category label
  691. * \param pcats pointer to Categories structure
  692. *
  693. * \return -1 on error
  694. * \return 0 if null value detected
  695. * \return 1 on success
  696. */
  697. int Rast_set_c_cat(const CELL * rast1, const CELL * rast2,
  698. const char *label, struct Categories *pcats)
  699. {
  700. return Rast_set_cat(rast1, rast2, label, pcats, CELL_TYPE);
  701. }
  702. /*!
  703. * \brief Set a raster category label (FCELL)
  704. *
  705. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  706. * category structure <i>pcats</i>.
  707. *
  708. * \param rast1, rast2 raster values (range)
  709. * \param label category label
  710. * \param pcats pointer to Categories structure
  711. *
  712. * \return
  713. */
  714. int Rast_set_f_cat(const FCELL * rast1, const FCELL * rast2,
  715. const char *label, struct Categories *pcats)
  716. {
  717. return Rast_set_cat(rast1, rast2, label, pcats, FCELL_TYPE);
  718. }
  719. /*!
  720. * \brief Set a raster category label (DCELL)
  721. *
  722. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  723. * category structure <i>pcats</i>.
  724. *
  725. * \param rast1, rast2 raster values (range)
  726. * \param label category label
  727. * \param pcats pointer to Categories structure
  728. *
  729. * \return -1 on error
  730. * \return 0 if null value detected
  731. * \return 1 on success
  732. */
  733. int Rast_set_d_cat(const DCELL * rast1, const DCELL * rast2,
  734. const char *label, struct Categories *pcats)
  735. {
  736. long len;
  737. DCELL dtmp1, dtmp2;
  738. int i;
  739. char *descr;
  740. /* DEBUG fprintf(stderr,"Rast_set_d_cat(rast1 = %p,rast2 = %p,label = '%s',pcats = %p)\n",
  741. rast1,rast2,label,pcats); */
  742. if (Rast_is_d_null_value(rast1))
  743. return 0;
  744. if (Rast_is_d_null_value(rast2))
  745. return 0;
  746. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): adding quant rule: %f %f %d %d\n", *rast1, *rast2, pcats->ncats, pcats->ncats); */
  747. /* the set_cat() functions are used in many places to reset the labels
  748. for the range (or cat) with existing label. In this case we don't
  749. want to store both rules with identical range even though the result
  750. of get_cat() will be correct, since it will use rule added later.
  751. we don't want to overuse memory and we don't want rules which are
  752. not used to be written out in cats file. So we first look if
  753. the label for this range has been sen, and if it has, overwrite it */
  754. for (i = 0; i < pcats->ncats; i++) {
  755. descr = Rast_get_ith_d_cat(pcats, i, &dtmp1, &dtmp2);
  756. if ((dtmp1 == *rast1 && dtmp2 == *rast2)
  757. || (dtmp1 == *rast2 && dtmp2 == *rast1)) {
  758. if (pcats->labels[i] != NULL)
  759. G_free(pcats->labels[i]);
  760. pcats->labels[i] = G_store(label);
  761. G_newlines_to_spaces(pcats->labels[i]);
  762. G_strip(pcats->labels[i]);
  763. return 1;
  764. }
  765. }
  766. /* when rule for this range does not exist */
  767. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): New rule: adding %d %p\n", i, pcats->labels); */
  768. Rast_quant_add_rule(&pcats->q, *rast1, *rast2, pcats->ncats,
  769. pcats->ncats);
  770. pcats->ncats++;
  771. if (pcats->nalloc < pcats->ncats) {
  772. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): need more space nalloc = %d ncats = %d\n", pcats->nalloc,pcats->ncats); */
  773. len = (pcats->nalloc + 256) * sizeof(char *);
  774. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): allocating %d labels(%d)\n", pcats->nalloc + 256,(int)len); */
  775. if (len != (int)len) { /* make sure len doesn't overflow int */
  776. pcats->ncats--;
  777. return -1;
  778. }
  779. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): pcats->nalloc = %d, pcats->labels = (%p), len = %d\n",pcats->nalloc,pcats->labels,(int)len); */
  780. if (pcats->nalloc) {
  781. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): Realloc-ing pcats->labels (%p)\n",pcats->labels); */
  782. pcats->labels =
  783. (char **)G_realloc((char *)pcats->labels, (int)len);
  784. }
  785. else {
  786. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): alloc-ing new labels pointer array\n"); */
  787. pcats->labels = (char **)G_malloc((int)len);
  788. }
  789. /* fflush(stderr); */
  790. /* DEBUG fprintf (stderr, "Rast_set_d_cats(): allocating %d marks(%d)\n", pcats->nalloc + 256,(int)len); */
  791. len = (pcats->nalloc + 256) * sizeof(int);
  792. if (len != (int)len) { /* make sure len doesn't overflow int */
  793. pcats->ncats--;
  794. return -1;
  795. }
  796. if (pcats->nalloc)
  797. pcats->marks = (int *)G_realloc((char *)pcats->marks, (int)len);
  798. else
  799. pcats->marks = (int *)G_malloc((int)len);
  800. pcats->nalloc += 256;
  801. }
  802. /* DEBUG fprintf(stderr,"Rast_set_d_cats(): store new label\n"); */
  803. pcats->labels[pcats->ncats - 1] = G_store(label);
  804. G_newlines_to_spaces(pcats->labels[pcats->ncats - 1]);
  805. G_strip(pcats->labels[pcats->ncats - 1]);
  806. /* DEBUG
  807. fprintf (stderr, "%d %s\n", pcats->ncats - 1, pcats->labels[pcats->ncats - 1]);
  808. */
  809. /* updates cats.num = max cat values. This is really just used in old
  810. raster programs, and I am doing it for backwards cmpatibility (Olga) */
  811. if ((CELL) * rast1 > pcats->num)
  812. pcats->num = (CELL) * rast1;
  813. if ((CELL) * rast2 > pcats->num)
  814. pcats->num = (CELL) * rast2;
  815. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): done\n"); */
  816. /* DEBUG fflush(stderr); */
  817. return 1;
  818. }
  819. /*!
  820. * \brief Set a raster category label
  821. *
  822. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  823. * category structure <i>pcats</i>.
  824. *
  825. * \param rast1, rast2 raster values (range)
  826. * \param label category label
  827. * \param pcats pointer to Categories structure
  828. * \param data_type map type
  829. *
  830. * \return -1 on error
  831. * \return 0 if null value detected
  832. * \return 1 on success
  833. */
  834. int Rast_set_cat(const void *rast1, const void *rast2,
  835. const char *label,
  836. struct Categories *pcats, RASTER_MAP_TYPE data_type)
  837. {
  838. DCELL val1, val2;
  839. val1 = Rast_get_d_value(rast1, data_type);
  840. val2 = Rast_get_d_value(rast2, data_type);
  841. return Rast_set_d_cat(&val1, &val2, label, pcats);
  842. }
  843. /*!
  844. * \brief Write raster category file
  845. *
  846. * \todo To be removed, replaced by Rast_write_cats().
  847. *
  848. * Writes the category file for the raster map <i>name</i> in the
  849. * current mapset from the <i>cats</i> structure.
  850. *
  851. * \param name map name
  852. * \param cats pointer to Categories structure
  853. *
  854. * \return void
  855. */
  856. void Rast_write_cats(const char *name, struct Categories *cats)
  857. {
  858. write_cats("cats", name, cats);
  859. }
  860. /*!
  861. * \brief Write vector category file
  862. *
  863. * <b>Note:</b> Used for only old vector format!
  864. *
  865. * \todo Move to the vector library.
  866. *
  867. * \param name map name
  868. * \param cats pointer to Categories structure
  869. *
  870. * \return void
  871. */
  872. void Rast_write_vector_cats(const char *name, struct Categories *cats)
  873. {
  874. write_cats("dig_cats", name, cats);
  875. }
  876. static void write_cats(const char *element, const char *name,
  877. struct Categories *cats)
  878. {
  879. FILE *fd;
  880. int i, fp_map;
  881. char *descr;
  882. DCELL val1, val2;
  883. char str1[100], str2[100];
  884. fd = G_fopen_new(element, name);
  885. if (!fd)
  886. G_fatal_error(_("Unable to open %s file for map <%s>"), element, name);
  887. /* write # cats - note # indicate 3.0 or later */
  888. fprintf(fd, "# %ld categories\n", (long)cats->num);
  889. /* title */
  890. fprintf(fd, "%s\n", cats->title != NULL ? cats->title : "");
  891. /* write format and coefficients */
  892. fprintf(fd, "%s\n", cats->fmt != NULL ? cats->fmt : "");
  893. fprintf(fd, "%.2f %.2f %.2f %.2f\n",
  894. cats->m1, cats->a1, cats->m2, cats->a2);
  895. /* if the map is integer or if this is a vector map, sort labels */
  896. if (strncmp(element, "dig", 3) == 0)
  897. fp_map = 0;
  898. else
  899. fp_map = Rast_map_is_fp(name, G_mapset());
  900. if (!fp_map)
  901. Rast_sort_cats(cats);
  902. /* write the cat numbers:label */
  903. for (i = 0; i < Rast_quant_nof_rules(&cats->q); i++) {
  904. descr = Rast_get_ith_d_cat(cats, i, &val1, &val2);
  905. if ((cats->fmt && cats->fmt[0])
  906. || (descr && descr[0])) {
  907. if (val1 == val2) {
  908. sprintf(str1, "%.10f", val1);
  909. G_trim_decimal(str1);
  910. fprintf(fd, "%s:%s\n", str1, descr != NULL ? descr : "");
  911. }
  912. else {
  913. sprintf(str1, "%.10f", val1);
  914. G_trim_decimal(str1);
  915. sprintf(str2, "%.10f", val2);
  916. G_trim_decimal(str2);
  917. fprintf(fd, "%s:%s:%s\n", str1, str2,
  918. descr != NULL ? descr : "");
  919. }
  920. }
  921. }
  922. fclose(fd);
  923. }
  924. /*!
  925. * \brief Get category description (DCELL)
  926. *
  927. * Returns i-th description and i-th data range from the list of
  928. * category descriptions with corresponding data ranges. end points of
  929. * data interval in <i>rast1</i> and <i>rast2</i>.
  930. *
  931. * \param pcats pointer to Categories structure
  932. * \param i index
  933. * \param rast1, rast2 raster values (range)
  934. *
  935. * \return "" on error
  936. * \return pointer to category description
  937. */
  938. char *Rast_get_ith_d_cat(const struct Categories *pcats,
  939. int i, DCELL * rast1, DCELL * rast2)
  940. {
  941. int index;
  942. if (i > pcats->ncats) {
  943. Rast_set_d_null_value(rast1, 1);
  944. Rast_set_d_null_value(rast2, 1);
  945. return "";
  946. }
  947. Rast_quant_get_ith_rule(&pcats->q, i, rast1, rast2, &index, &index);
  948. return pcats->labels[index];
  949. }
  950. /*!
  951. * \brief Get category description (FCELL)
  952. *
  953. * Returns i-th description and i-th data range from the list of
  954. * category descriptions with corresponding data ranges. end points of
  955. * data interval in <i>rast1</i> and <i>rast2</i>.
  956. *
  957. * \param pcats pointer to Categories structure
  958. * \param i index
  959. * \param rast1, rast2 raster values (range)
  960. *
  961. * \return "" on error
  962. * \return pointer to category description
  963. */
  964. char *Rast_get_ith_f_cat(const struct Categories *pcats,
  965. int i, void *rast1, void *rast2)
  966. {
  967. RASTER_MAP_TYPE data_type = FCELL_TYPE;
  968. char *tmp;
  969. DCELL val1, val2;
  970. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  971. Rast_set_d_value(rast1, val1, data_type);
  972. Rast_set_d_value(rast2, val2, data_type);
  973. return tmp;
  974. }
  975. /*!
  976. * \brief Get category description (CELL)
  977. *
  978. * Returns i-th description and i-th data range from the list of
  979. * category descriptions with corresponding data ranges. end points of
  980. * data interval in <i>rast1</i> and <i>rast2</i>.
  981. *
  982. * \param pcats pointer to Categories structure
  983. * \param i index
  984. * \param rast1, rast2 raster values (range)
  985. *
  986. * \return "" on error
  987. * \return pointer to category description
  988. */
  989. char *Rast_get_ith_c_cat(const struct Categories *pcats,
  990. int i, void *rast1, void *rast2)
  991. {
  992. RASTER_MAP_TYPE data_type = CELL_TYPE;
  993. char *tmp;
  994. DCELL val1, val2;
  995. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  996. Rast_set_d_value(rast1, val1, data_type);
  997. Rast_set_d_value(rast2, val2, data_type);
  998. return tmp;
  999. }
  1000. /*!
  1001. * \brief Get category description
  1002. *
  1003. * Returns i-th description and i-th data range from the list of
  1004. * category descriptions with corresponding data ranges. end points of
  1005. * data interval in <i>rast1</i> and <i>rast2</i>.
  1006. *
  1007. * \param pcats pointer to Categories structure
  1008. * \param i index
  1009. * \param rast1, rast2 raster values (range)
  1010. * \param data_type map type
  1011. *
  1012. * \return "" on error
  1013. * \return pointer to category description
  1014. */
  1015. char *Rast_get_ith_cat(const struct Categories *pcats, int i, void *rast1,
  1016. void *rast2, RASTER_MAP_TYPE data_type)
  1017. {
  1018. char *tmp;
  1019. DCELL val1, val2;
  1020. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  1021. Rast_set_d_value(rast1, val1, data_type);
  1022. Rast_set_d_value(rast2, val2, data_type);
  1023. return tmp;
  1024. }
  1025. /*!
  1026. * \brief Initialize category structure
  1027. *
  1028. * To construct a new category file, the structure must first be
  1029. * initialized. This routine initializes the <i>cats</i> structure,
  1030. * and copies the <i>title</i> into the structure. The number of
  1031. * categories is set initially to <i>n</i>.
  1032. *
  1033. * For example:
  1034. \code
  1035. struct Categories cats;
  1036. Rast_init_cats ("", &cats);
  1037. \endcode
  1038. *
  1039. * \todo Eliminate pcats->num. Num has no meaning in new Categories
  1040. * structure and only stores (int) largets data value for backwards
  1041. * compatibility.
  1042. *
  1043. * \param title title
  1044. * \param pcats pointer to Categories structure
  1045. */
  1046. void Rast_init_cats(const char *title, struct Categories *pcats)
  1047. {
  1048. Rast_set_cats_title(title, pcats);
  1049. pcats->labels = NULL;
  1050. pcats->nalloc = 0;
  1051. pcats->ncats = 0;
  1052. pcats->num = 0;
  1053. pcats->fmt = NULL;
  1054. pcats->m1 = 0.0;
  1055. pcats->a1 = 0.0;
  1056. pcats->m2 = 0.0;
  1057. pcats->a2 = 0.0;
  1058. pcats->last_marked_rule = -1;
  1059. Rast_quant_init(&pcats->q);
  1060. }
  1061. /*!
  1062. * \brief Set title in category structure
  1063. *
  1064. * \todo To be removed, replaced by Rast_set_cats_title().
  1065. *
  1066. * The <i>title</i> is copied into the <i>pcats</i> structure.
  1067. *
  1068. * \param title title
  1069. * \param pcats pointer to Categories structure
  1070. */
  1071. void Rast_set_cats_title(const char *title, struct Categories *pcats)
  1072. {
  1073. if (title == NULL)
  1074. title = "";
  1075. pcats->title = G_store(title);
  1076. G_newlines_to_spaces(pcats->title);
  1077. G_strip(pcats->title);
  1078. }
  1079. /*!
  1080. \brief Set category fmt (?)
  1081. \param fmt
  1082. \param m1
  1083. \param a1
  1084. \param m2
  1085. \param a2
  1086. \param pcats pointer to Categories structure
  1087. */
  1088. void Rast_set_cats_fmt(const char *fmt, double m1, double a1, double m2,
  1089. double a2, struct Categories *pcats)
  1090. {
  1091. pcats->m1 = m1;
  1092. pcats->a1 = a1;
  1093. pcats->m2 = m2;
  1094. pcats->a2 = a2;
  1095. pcats->fmt = G_store(fmt);
  1096. G_newlines_to_spaces(pcats->fmt);
  1097. G_strip(pcats->fmt);
  1098. }
  1099. /*!
  1100. * \brief Free category structure memory
  1101. *
  1102. * \todo To be removed, replaced by Rast_free_cats().
  1103. *
  1104. * Frees memory allocated by Rast_read_cats(), Rast_init_cats() and
  1105. * Rast_set_c_cat().
  1106. *
  1107. * \param pcats pointer to Categories structure
  1108. */
  1109. void Rast_free_cats(struct Categories *pcats)
  1110. {
  1111. int i;
  1112. if (pcats->title != NULL) {
  1113. G_free(pcats->title);
  1114. pcats->title = NULL;
  1115. }
  1116. if (pcats->fmt != NULL) {
  1117. G_free(pcats->fmt);
  1118. pcats->fmt = NULL;
  1119. }
  1120. if (pcats->ncats > 0) {
  1121. for (i = 0; i < pcats->ncats; i++)
  1122. if (pcats->labels[i] != NULL)
  1123. G_free(pcats->labels[i]);
  1124. G_free(pcats->labels);
  1125. G_free(pcats->marks);
  1126. pcats->labels = NULL;
  1127. }
  1128. Rast_quant_free(&pcats->q);
  1129. pcats->ncats = 0;
  1130. pcats->nalloc = 0;
  1131. }
  1132. /*!
  1133. * \brief Copy raster categories
  1134. *
  1135. * Allocates NEW space for quant rules and labels n <i>pcats_to</i>
  1136. * and copies all info from <i>pcats_from</i> cats to
  1137. * <i>pcats_to</i> cats.
  1138. *
  1139. * \param pcats_to pointer to destination Categories structure
  1140. * \param pcats_from pointer to source Categories structure
  1141. */
  1142. void Rast_copy_cats(struct Categories *pcats_to,
  1143. const struct Categories *pcats_from)
  1144. {
  1145. int i;
  1146. char *descr;
  1147. DCELL d1, d2;
  1148. Rast_init_cats(pcats_from->title, pcats_to);
  1149. for (i = 0; i < pcats_from->ncats; i++) {
  1150. descr = Rast_get_ith_d_cat(pcats_from, i, &d1, &d2);
  1151. Rast_set_d_cat(&d1, &d2, descr, pcats_to);
  1152. }
  1153. }
  1154. /*!
  1155. \brief Get number of raster categories
  1156. \param pcats pointer to Categories structure
  1157. \return number of categories
  1158. */
  1159. int Rast_number_of_cats(struct Categories *pcats)
  1160. {
  1161. return pcats->ncats;
  1162. }
  1163. /*!
  1164. \brief Sort categories
  1165. \param pcats pointer to Categories structure
  1166. \return -1 on error (nothing to sort)
  1167. \return 0 on success
  1168. */
  1169. int Rast_sort_cats(struct Categories *pcats)
  1170. {
  1171. int *indexes, i, ncats;
  1172. char *descr;
  1173. DCELL d1, d2;
  1174. if (pcats->ncats <= 1)
  1175. return -1;
  1176. ncats = pcats->ncats;
  1177. G_debug(3, "Rast_sort_cats(): Copying to save cats buffer");
  1178. Rast_copy_cats(&save_cats, pcats);
  1179. Rast_free_cats(pcats);
  1180. indexes = (int *)G_malloc(sizeof(int) * ncats);
  1181. for (i = 0; i < ncats; i++)
  1182. indexes[i] = i;
  1183. qsort(indexes, ncats, sizeof(int), cmp);
  1184. Rast_init_cats(save_cats.title, pcats);
  1185. for (i = 0; i < ncats; i++) {
  1186. descr = Rast_get_ith_d_cat(&save_cats, indexes[i], &d1, &d2);
  1187. G_debug(4, " Write sorted cats, pcats = %p pcats->labels = %p",
  1188. (void *)pcats, (void *)pcats->labels);
  1189. Rast_set_d_cat(&d1, &d2, descr, pcats);
  1190. }
  1191. Rast_free_cats(&save_cats);
  1192. return 0;
  1193. }
  1194. static int cmp(const void *aa, const void *bb)
  1195. {
  1196. const int *a = aa, *b = bb;
  1197. DCELL min_rast1, min_rast2, max_rast1, max_rast2;
  1198. CELL index;
  1199. Rast_quant_get_ith_rule(&(save_cats.q), *a,
  1200. &min_rast1, &max_rast1, &index, &index);
  1201. Rast_quant_get_ith_rule(&(save_cats.q), *b,
  1202. &min_rast2, &max_rast2, &index, &index);
  1203. if (min_rast1 < min_rast2)
  1204. return -1;
  1205. if (min_rast1 > min_rast2)
  1206. return 1;
  1207. return 0;
  1208. }