cats.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  1. /*!
  2. * \file 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 coefficent lins 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 cat;
  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 (cat = 0;; cat++) {
  221. char label[1024];
  222. if (G_getl(buff, sizeof buff, fd) == 0)
  223. break;
  224. if (old)
  225. Rast_set_c_cat(&cat, &cat, 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 (sscanf(buff, "%d:%[^\n]", &cat, label) >= 1)
  238. Rast_set_cat(&cat, &cat, label, pcats, CELL_TYPE);
  239. else if (sscanf(buff, "%lf:%[^\n]", &val1, label) >= 1)
  240. Rast_set_cat(&val1, &val1, label, pcats, DCELL_TYPE);
  241. else
  242. goto error;
  243. }
  244. }
  245. fclose(fd);
  246. return 0;
  247. error:
  248. fclose(fd);
  249. return -1;
  250. }
  251. /*!
  252. * \brief Get title from category structure struct
  253. *
  254. * \todo Remove from GIS Library, replace by Rast_get_c_cats_title().
  255. *
  256. * Map layers store a one-line title in the category structure as
  257. * well. This routine returns a pointer to the title contained in the
  258. * <i>cats</i> structure. A legal pointer is always returned. If the
  259. * map layer does not have a title, then a pointer to the empty string
  260. * "" is returned.
  261. *
  262. * \param pcats pointer to Categories structure
  263. *
  264. * \return title
  265. * \return "" if missing
  266. */
  267. char *Rast_get_cats_title(const struct Categories *pcats)
  268. {
  269. return pcats->title ? pcats->title : "";
  270. }
  271. /*!
  272. * \brief Get a raster category label (CELL)
  273. *
  274. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  275. * structure and returns a pointer to a string which is the label for
  276. * the category. A legal pointer is always returned. If the category
  277. * does not exist in <i>pcats</i>, then a pointer to the empty string
  278. * "" is returned.
  279. *
  280. * <b>Warning:</b> The pointer that is returned points to a hidden
  281. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  282. * buffer.
  283. *
  284. * \param rast cell value
  285. * \param pcats pointer to Categories structure
  286. *
  287. * \return pointer to category label
  288. * \return "" if category is not found
  289. */
  290. char *Rast_get_c_cat(CELL * rast, struct Categories *pcats)
  291. {
  292. return Rast_get_cat(rast, pcats, CELL_TYPE);
  293. }
  294. /*!
  295. * \brief Get a raster category label (FCELL)
  296. *
  297. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  298. * structure and returns a pointer to a string which is the label for
  299. * the category. A legal pointer is always returned. If the category
  300. * does not exist in <i>pcats</i>, then a pointer to the empty string
  301. * "" is returned.
  302. *
  303. * <b>Warning:</b> The pointer that is returned points to a hidden
  304. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  305. * buffer.
  306. *
  307. * \param rast cell value
  308. * \param pcats pointer to Categories structure
  309. *
  310. * \return pointer to category label
  311. * \return "" if category is not found
  312. */
  313. char *Rast_get_f_cat(FCELL * rast, struct Categories *pcats)
  314. {
  315. return Rast_get_cat(rast, pcats, FCELL_TYPE);
  316. }
  317. /*!
  318. * \brief Get a raster category label (DCELL)
  319. *
  320. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  321. * structure and returns a pointer to a string which is the label for
  322. * the category. A legal pointer is always returned. If the category
  323. * does not exist in <i>pcats</i>, then a pointer to the empty string
  324. * "" is returned.
  325. *
  326. * <b>Warning:</b> The pointer that is returned points to a hidden
  327. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  328. * buffer.
  329. *
  330. * \param rast cell value
  331. * \param pcats pointer to Categories structure
  332. *
  333. * \return pointer to category label
  334. * \return "" if category is not found
  335. */
  336. char *Rast_get_d_cat(DCELL * rast, struct Categories *pcats)
  337. {
  338. return Rast_get_cat(rast, pcats, DCELL_TYPE);
  339. }
  340. /*!
  341. * \brief Get a raster category label
  342. *
  343. * This routine looks up category <i>rast</i> in the <i>pcats</i>
  344. * structure and returns a pointer to a string which is the label for
  345. * the category. A legal pointer is always returned. If the category
  346. * does not exist in <i>pcats</i>, then a pointer to the empty string
  347. * "" is returned.
  348. *
  349. * <b>Warning:</b> The pointer that is returned points to a hidden
  350. * static buffer. Successive calls to Rast_get_c_cat() overwrite this
  351. * buffer.
  352. *
  353. * \param rast cell value
  354. * \param pcats pointer to Categories structure
  355. * \param data_type map type (CELL, FCELL, DCELL)
  356. *
  357. * \return pointer to category label
  358. * \return "" if category is not found
  359. */
  360. char *Rast_get_cat(void *rast,
  361. struct Categories *pcats, RASTER_MAP_TYPE data_type)
  362. {
  363. static char label[1024];
  364. char *f, *l, *v;
  365. CELL i;
  366. DCELL val;
  367. float a[2];
  368. char fmt[30], value_str[30];
  369. if (Rast_is_null_value(rast, data_type)) {
  370. sprintf(label, "no data");
  371. return label;
  372. }
  373. /* first search the list of labels */
  374. *label = 0;
  375. val = Rast_get_d_value(rast, data_type);
  376. i = Rast_quant_get_cell_value(&pcats->q, val);
  377. G_debug(5, "Rast_get_cat(): val %lf found i %d", val, i);
  378. if (!Rast_is_c_null_value(&i) && i < pcats->ncats) {
  379. if (pcats->labels[i] != NULL)
  380. return pcats->labels[i];
  381. return label;
  382. }
  383. /* generate the label */
  384. if ((f = pcats->fmt) == NULL)
  385. return label;
  386. a[0] = (float)val *pcats->m1 + pcats->a1;
  387. a[1] = (float)val *pcats->m2 + pcats->a2;
  388. l = label;
  389. while (*f) {
  390. if (*f == '$') {
  391. f++;
  392. if (*f == '$')
  393. *l++ = *f++;
  394. else if (*f == '?') {
  395. f++;
  396. get_cond(&f, v = value_str, val);
  397. while (*v)
  398. *l++ = *v++;
  399. }
  400. else if (get_fmt(&f, fmt, &i)) {
  401. sprintf(v = value_str, fmt, a[i]);
  402. while (*v)
  403. *l++ = *v++;
  404. }
  405. else
  406. *l++ = '$';
  407. }
  408. else {
  409. *l++ = *f++;
  410. }
  411. }
  412. *l = 0;
  413. return label;
  414. }
  415. /*!
  416. * \brief Sets marks for all categories to 0.
  417. *
  418. * This initializes Categories structure for subsequest calls to
  419. * Rast_mark_cats() for each row of data, where non-zero mark for
  420. * i-th label means that some of the cells in rast_row are labeled
  421. * with i-th label and fall into i-th data range. These marks help
  422. * determine from the Categories structure which labels were used and
  423. * which weren't.
  424. *
  425. * \param pcats pointer to Categories structure
  426. */
  427. void Rast_unmark_cats(struct Categories *pcats)
  428. {
  429. int i;
  430. for (i = 0; i < pcats->ncats; i++)
  431. pcats->marks[i] = 0;
  432. }
  433. /*!
  434. * \brief Looks up the category label for each raster value (CELL).
  435. *
  436. * Looks up the category label for each raster value in the
  437. * <i>rast_row</i> and updates the marks for labels found.
  438. *
  439. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  440. * raster cells read so far which are labeled with i-th label and fall
  441. * into i-th data range.
  442. *
  443. * \param rast_row raster row to update stats
  444. * \param ncols number of columns
  445. * \param pcats pointer to Categories structure
  446. *
  447. */
  448. void Rast_mark_c_cats(const CELL * rast_row,
  449. int ncols, struct Categories *pcats)
  450. {
  451. Rast_mark_cats(rast_row, ncols, pcats, CELL_TYPE);
  452. }
  453. /*!
  454. * \brief Looks up the category label for each raster value (FCELL).
  455. *
  456. * Looks up the category label for each raster value in the
  457. * <i>rast_row</i> and updates the marks for labels found.
  458. *
  459. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  460. * raster cells read so far which are labeled with i-th label and fall
  461. * into i-th data range.
  462. *
  463. * \param rast_row raster row to update stats
  464. * \param ncols number of columns
  465. * \param pcats pointer to Categories structure
  466. *
  467. */
  468. void Rast_mark_f_cats(const FCELL * rast_row,
  469. int ncols, struct Categories *pcats)
  470. {
  471. Rast_mark_cats(rast_row, ncols, pcats, FCELL_TYPE);
  472. }
  473. /*!
  474. * \brief Looks up the category label for each raster value (DCELL).
  475. *
  476. * Looks up the category label for each raster value in the
  477. * <i>rast_row</i> and updates the marks for labels found.
  478. *
  479. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  480. * raster cells read so far which are labeled with i-th label and fall
  481. * into i-th data range.
  482. *
  483. * \param rast_row raster row to update stats
  484. * \param ncols number of columns
  485. * \param pcats pointer to Categories structure
  486. *
  487. */
  488. void Rast_mark_d_cats(const DCELL * rast_row,
  489. int ncols, struct Categories *pcats)
  490. {
  491. Rast_mark_cats(rast_row, ncols, pcats, DCELL_TYPE);
  492. }
  493. /*!
  494. * \brief Looks up the category label for each raster value (DCELL).
  495. *
  496. * Looks up the category label for each raster value in the
  497. * <i>rast_row</i> and updates the marks for labels found.
  498. *
  499. * <b>Note:</b> Non-zero mark for i-th label stores the number of of
  500. * raster cells read so far which are labeled with i-th label and fall
  501. * into i-th data range.
  502. *
  503. * \param rast_row raster row to update stats
  504. * \param ncols number of columns
  505. * \param pcats pointer to Categories structure
  506. * \param data_type map type
  507. *
  508. * \return -1 on error
  509. * \return 1 on success
  510. */
  511. int Rast_mark_cats(const void *rast_row,
  512. int ncols, struct Categories *pcats,
  513. RASTER_MAP_TYPE data_type)
  514. {
  515. size_t size = Rast_cell_size(data_type);
  516. CELL i;
  517. while (ncols-- > 0) {
  518. i = Rast_quant_get_cell_value(&pcats->q,
  519. Rast_get_d_value(rast_row, data_type));
  520. if (Rast_is_c_null_value(&i))
  521. continue;
  522. if (i > pcats->ncats)
  523. return -1;
  524. pcats->marks[i]++;
  525. rast_row = G_incr_void_ptr(rast_row, size);
  526. }
  527. return 1;
  528. }
  529. /*!
  530. * \brief Rewind raster categories
  531. *
  532. * After call to this function Rast_get_next_marked_cat() returns
  533. * the first marked cat label.
  534. *
  535. * \param pcats pointer to Categories structure
  536. */
  537. void Rast_rewind_cats(struct Categories *pcats)
  538. {
  539. pcats->last_marked_rule = -1;
  540. }
  541. /*!
  542. \brief Get next marked raster categories (DCELL)
  543. \param pcats pointer to Categories structure
  544. \param rast1, rast2 cell values (raster range)
  545. \param[out] count count
  546. \return NULL if not found
  547. \return description if found
  548. */
  549. char *Rast_get_next_marked_d_cat(struct Categories *pcats,
  550. DCELL * rast1, DCELL * rast2, long *count)
  551. {
  552. char *descr = NULL;
  553. int found, i;
  554. found = 0;
  555. /* pcats->ncats should be == Rast_quant_nof_rules(&pcats->q) */
  556. G_debug(3, "last marked %d nrules %d\n", pcats->last_marked_rule,
  557. Rast_quant_nof_rules(&pcats->q));
  558. for (i = pcats->last_marked_rule + 1; i < Rast_quant_nof_rules(&pcats->q);
  559. i++) {
  560. descr = Rast_get_ith_d_cat(pcats, i, rast1, rast2);
  561. G_debug(5, "%d %d", i, pcats->marks[i]);
  562. if (pcats->marks[i]) {
  563. found = 1;
  564. break;
  565. }
  566. }
  567. if (!found)
  568. return NULL;
  569. *count = pcats->marks[i];
  570. pcats->last_marked_rule = i;
  571. return descr;
  572. }
  573. /*!
  574. \brief Get next marked raster categories (CELL)
  575. \param pcats pointer to Categories structure
  576. \param rast1, rast2 cell values (raster range)
  577. \param[out] count count
  578. \return NULL if not found
  579. \return description if found
  580. */
  581. char *Rast_get_next_marked_c_cat(struct Categories *pcats,
  582. CELL * rast1, CELL * rast2, long *count)
  583. {
  584. return Rast_get_next_marked_cat(pcats, rast1, rast2, count, CELL_TYPE);
  585. }
  586. /*!
  587. \brief Get next marked raster categories (FCELL)
  588. \param pcats pointer to Categories structure
  589. \param rast1, rast2 cell values (raster range)
  590. \param[out] count count
  591. \return NULL if not found
  592. \return description if found
  593. */
  594. char *Rast_get_next_marked_f_cat(struct Categories *pcats,
  595. FCELL * rast1, FCELL * rast2, long *count)
  596. {
  597. return Rast_get_next_marked_cat(pcats, rast1, rast2, count, FCELL_TYPE);
  598. }
  599. /*!
  600. \brief Get next marked raster categories
  601. \param pcats pointer to Categories structure
  602. \param rast1, rast2 cell values (raster range)
  603. \param[out] count count
  604. \param data_type map type
  605. \return NULL if not found
  606. \return description if found
  607. */
  608. char *Rast_get_next_marked_cat(struct Categories *pcats,
  609. void *rast1, void *rast2,
  610. long *count, RASTER_MAP_TYPE data_type)
  611. {
  612. DCELL val1, val2;
  613. char *lab;
  614. lab = Rast_get_next_marked_d_cat(pcats, &val1, &val2, count);
  615. Rast_set_d_value(rast1, val1, data_type);
  616. Rast_set_d_value(rast2, val2, data_type);
  617. return lab;
  618. }
  619. static int get_fmt(char **f, char *fmt, int *i)
  620. {
  621. char *ff;
  622. ff = *f;
  623. if (*ff == 0)
  624. return 0;
  625. if (*ff == '$') {
  626. *f = ff + 1;
  627. return 0;
  628. }
  629. switch (*ff++) {
  630. case '1':
  631. *i = 0;
  632. break;
  633. case '2':
  634. *i = 1;
  635. break;
  636. default:
  637. return 0;
  638. }
  639. *fmt++ = '%';
  640. *fmt++ = '.';
  641. if (*ff++ != '.') {
  642. *f = ff - 1;
  643. *fmt++ = '0';
  644. *fmt++ = 'f';
  645. *fmt = 0;
  646. return 1;
  647. }
  648. *fmt = '0';
  649. while (*ff >= '0' && *ff <= '9')
  650. *fmt++ = *ff++;
  651. *fmt++ = 'f';
  652. *fmt = 0;
  653. *f = ff;
  654. return 1;
  655. }
  656. static void get_cond(char **f, char *value, DCELL val)
  657. {
  658. char *ff;
  659. ff = *f;
  660. if (val == 1.) {
  661. while (*ff)
  662. if (*ff++ == '$')
  663. break;
  664. }
  665. while (*ff)
  666. if (*ff == '$') {
  667. ff++;
  668. break;
  669. }
  670. else
  671. *value++ = *ff++;
  672. if (val != 1.) {
  673. while (*ff)
  674. if (*ff++ == '$')
  675. break;
  676. }
  677. *value = 0;
  678. *f = ff;
  679. }
  680. /*!
  681. * \brief Set a raster category label (CELL)
  682. *
  683. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  684. * category structure <i>pcats</i>.
  685. *
  686. * \param rast1, rast2 raster values (range)
  687. * \param label category label
  688. * \param pcats pointer to Categories structure
  689. *
  690. * \return -1 on error
  691. * \return 0 if null value detected
  692. * \return 1 on success
  693. */
  694. int Rast_set_c_cat(const CELL * rast1, const CELL * rast2,
  695. const char *label, struct Categories *pcats)
  696. {
  697. return Rast_set_cat(rast1, rast2, label, pcats, CELL_TYPE);
  698. }
  699. /*!
  700. * \brief Set a raster category label (FCELL)
  701. *
  702. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  703. * category structure <i>pcats</i>.
  704. *
  705. * \param rast1, rast2 raster values (range)
  706. * \param label category label
  707. * \param pcats pointer to Categories structure
  708. *
  709. * \return
  710. */
  711. int Rast_set_f_cat(const FCELL * rast1, const FCELL * rast2,
  712. const char *label, struct Categories *pcats)
  713. {
  714. return Rast_set_cat(rast1, rast2, label, pcats, FCELL_TYPE);
  715. }
  716. /*!
  717. * \brief Set a raster category label (DCELL)
  718. *
  719. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  720. * category structure <i>pcats</i>.
  721. *
  722. * \param rast1, rast2 raster values (range)
  723. * \param label category label
  724. * \param pcats pointer to Categories structure
  725. *
  726. * \return -1 on error
  727. * \return 0 if null value detected
  728. * \return 1 on success
  729. */
  730. int Rast_set_d_cat(const DCELL * rast1, const DCELL * rast2,
  731. const char *label, struct Categories *pcats)
  732. {
  733. long len;
  734. DCELL dtmp1, dtmp2;
  735. int i;
  736. char *descr;
  737. /* DEBUG fprintf(stderr,"Rast_set_d_cat(rast1 = %p,rast2 = %p,label = '%s',pcats = %p)\n",
  738. rast1,rast2,label,pcats); */
  739. if (Rast_is_d_null_value(rast1))
  740. return 0;
  741. if (Rast_is_d_null_value(rast2))
  742. return 0;
  743. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): adding quant rule: %f %f %d %d\n", *rast1, *rast2, pcats->ncats, pcats->ncats); */
  744. /* the set_cat() functions are used in many places to reset the labels
  745. for the range (or cat) with existing label. In this case we don't
  746. want to store both rules with identical range even though the result
  747. of get_cat() will be correct, since it will use rule added later.
  748. we don't want to overuse memory and we don't want rules which are
  749. not used to be writen out in cats file. So we first look if
  750. the label for this range has been sen, and if it has, overwrite it */
  751. for (i = 0; i < pcats->ncats; i++) {
  752. descr = Rast_get_ith_d_cat(pcats, i, &dtmp1, &dtmp2);
  753. if ((dtmp1 == *rast1 && dtmp2 == *rast2)
  754. || (dtmp1 == *rast2 && dtmp2 == *rast1)) {
  755. if (pcats->labels[i] != NULL)
  756. G_free(pcats->labels[i]);
  757. pcats->labels[i] = G_store(label);
  758. G_newlines_to_spaces(pcats->labels[i]);
  759. G_strip(pcats->labels[i]);
  760. return 1;
  761. }
  762. }
  763. /* when rule for this range does not exist */
  764. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): New rule: adding %d %p\n", i, pcats->labels); */
  765. Rast_quant_add_rule(&pcats->q, *rast1, *rast2, pcats->ncats,
  766. pcats->ncats);
  767. pcats->ncats++;
  768. if (pcats->nalloc < pcats->ncats) {
  769. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): need more space nalloc = %d ncats = %d\n", pcats->nalloc,pcats->ncats); */
  770. len = (pcats->nalloc + 256) * sizeof(char *);
  771. /* DEBUG fprintf (stderr, "Rast_set_d_cat(): allocating %d labels(%d)\n", pcats->nalloc + 256,(int)len); */
  772. if (len != (int)len) { /* make sure len doesn't overflow int */
  773. pcats->ncats--;
  774. return -1;
  775. }
  776. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): pcats->nalloc = %d, pcats->labels = (%p), len = %d\n",pcats->nalloc,pcats->labels,(int)len); */
  777. if (pcats->nalloc) {
  778. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): Realloc-ing pcats->labels (%p)\n",pcats->labels); */
  779. pcats->labels =
  780. (char **)G_realloc((char *)pcats->labels, (int)len);
  781. }
  782. else {
  783. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): alloc-ing new labels pointer array\n"); */
  784. pcats->labels = (char **)G_malloc((int)len);
  785. }
  786. /* fflush(stderr); */
  787. /* DEBUG fprintf (stderr, "Rast_set_d_cats(): allocating %d marks(%d)\n", pcats->nalloc + 256,(int)len); */
  788. len = (pcats->nalloc + 256) * sizeof(int);
  789. if (len != (int)len) { /* make sure len doesn't overflow int */
  790. pcats->ncats--;
  791. return -1;
  792. }
  793. if (pcats->nalloc)
  794. pcats->marks = (int *)G_realloc((char *)pcats->marks, (int)len);
  795. else
  796. pcats->marks = (int *)G_malloc((int)len);
  797. pcats->nalloc += 256;
  798. }
  799. /* DEBUG fprintf(stderr,"Rast_set_d_cats(): store new label\n"); */
  800. pcats->labels[pcats->ncats - 1] = G_store(label);
  801. G_newlines_to_spaces(pcats->labels[pcats->ncats - 1]);
  802. G_strip(pcats->labels[pcats->ncats - 1]);
  803. /* DEBUG
  804. fprintf (stderr, "%d %s\n", pcats->ncats - 1, pcats->labels[pcats->ncats - 1]);
  805. */
  806. /* updates cats.num = max cat values. This is really just used in old
  807. raster programs, and I am doing it for backwards cmpatibility (Olga) */
  808. if ((CELL) * rast1 > pcats->num)
  809. pcats->num = (CELL) * rast1;
  810. if ((CELL) * rast2 > pcats->num)
  811. pcats->num = (CELL) * rast2;
  812. /* DEBUG fprintf(stderr,"Rast_set_d_cat(): done\n"); */
  813. /* DEBUG fflush(stderr); */
  814. return 1;
  815. }
  816. /*!
  817. * \brief Set a raster category label
  818. *
  819. * Adds the label for range <i>rast1</i> through <i>rast2</i> in
  820. * category structure <i>pcats</i>.
  821. *
  822. * \param rast1, rast2 raster values (range)
  823. * \param label category label
  824. * \param pcats pointer to Categories structure
  825. * \param data_type map type
  826. *
  827. * \return -1 on error
  828. * \return 0 if null value detected
  829. * \return 1 on success
  830. */
  831. int Rast_set_cat(const void *rast1, const void *rast2,
  832. const char *label,
  833. struct Categories *pcats, RASTER_MAP_TYPE data_type)
  834. {
  835. DCELL val1, val2;
  836. val1 = Rast_get_d_value(rast1, data_type);
  837. val2 = Rast_get_d_value(rast2, data_type);
  838. return Rast_set_d_cat(&val1, &val2, label, pcats);
  839. }
  840. /*!
  841. * \brief Write raster category file
  842. *
  843. * \todo To be removed, replaced by Rast_write_cats().
  844. *
  845. * Writes the category file for the raster map <i>name</i> in the
  846. * current mapset from the <i>cats</i> structure.
  847. *
  848. * \param name map name
  849. * \param cats pointer to Categories structure
  850. *
  851. * \return void
  852. */
  853. void Rast_write_cats(const char *name, struct Categories *cats)
  854. {
  855. write_cats("cats", name, cats);
  856. }
  857. /*!
  858. * \brief Write vector category file
  859. *
  860. * <b>Note:</b> Used for only old vector format!
  861. *
  862. * \todo Move to the vector library.
  863. *
  864. * \param name map name
  865. * \param cats pointer to Categories structure
  866. *
  867. * \return void
  868. */
  869. void Rast_write_vector_cats(const char *name, struct Categories *cats)
  870. {
  871. write_cats("dig_cats", name, cats);
  872. }
  873. static void write_cats(const char *element, const char *name,
  874. struct Categories *cats)
  875. {
  876. FILE *fd;
  877. int i, fp_map;
  878. char *descr;
  879. DCELL val1, val2;
  880. char str1[100], str2[100];
  881. fd = G_fopen_new(element, name);
  882. if (!fd)
  883. G_fatal_error(_("Unable to open %s file for map <%s>"), element, name);
  884. /* write # cats - note # indicate 3.0 or later */
  885. fprintf(fd, "# %ld categories\n", (long)cats->num);
  886. /* title */
  887. fprintf(fd, "%s\n", cats->title != NULL ? cats->title : "");
  888. /* write format and coefficients */
  889. fprintf(fd, "%s\n", cats->fmt != NULL ? cats->fmt : "");
  890. fprintf(fd, "%.2f %.2f %.2f %.2f\n",
  891. cats->m1, cats->a1, cats->m2, cats->a2);
  892. /* if the map is integer or if this is a vector map, sort labels */
  893. if (strncmp(element, "dig", 3) == 0)
  894. fp_map = 0;
  895. else
  896. fp_map = Rast_map_is_fp(name, G_mapset());
  897. if (!fp_map)
  898. Rast_sort_cats(cats);
  899. /* write the cat numbers:label */
  900. for (i = 0; i < Rast_quant_nof_rules(&cats->q); i++) {
  901. descr = Rast_get_ith_d_cat(cats, i, &val1, &val2);
  902. if ((cats->fmt && cats->fmt[0])
  903. || (descr && descr[0])) {
  904. if (val1 == val2) {
  905. sprintf(str1, "%.10f", val1);
  906. G_trim_decimal(str1);
  907. fprintf(fd, "%s:%s\n", str1, descr != NULL ? descr : "");
  908. }
  909. else {
  910. sprintf(str1, "%.10f", val1);
  911. G_trim_decimal(str1);
  912. sprintf(str2, "%.10f", val2);
  913. G_trim_decimal(str2);
  914. fprintf(fd, "%s:%s:%s\n", str1, str2,
  915. descr != NULL ? descr : "");
  916. }
  917. }
  918. }
  919. fclose(fd);
  920. }
  921. /*!
  922. * \brief Get category description (DCELL)
  923. *
  924. * Returns i-th description and i-th data range from the list of
  925. * category descriptions with corresponding data ranges. end points of
  926. * data interval in <i>rast1</i> and <i>rast2</i>.
  927. *
  928. * \param pcats pointer to Categories structure
  929. * \param i index
  930. * \param rast1, rast2 raster values (range)
  931. *
  932. * \return "" on error
  933. * \return pointer to category description
  934. */
  935. char *Rast_get_ith_d_cat(const struct Categories *pcats,
  936. int i, DCELL * rast1, DCELL * rast2)
  937. {
  938. int index;
  939. if (i > pcats->ncats) {
  940. Rast_set_d_null_value(rast1, 1);
  941. Rast_set_d_null_value(rast2, 1);
  942. return "";
  943. }
  944. Rast_quant_get_ith_rule(&pcats->q, i, rast1, rast2, &index, &index);
  945. return pcats->labels[index];
  946. }
  947. /*!
  948. * \brief Get category description (FCELL)
  949. *
  950. * Returns i-th description and i-th data range from the list of
  951. * category descriptions with corresponding data ranges. end points of
  952. * data interval in <i>rast1</i> and <i>rast2</i>.
  953. *
  954. * \param pcats pointer to Categories structure
  955. * \param i index
  956. * \param rast1, rast2 raster values (range)
  957. *
  958. * \return "" on error
  959. * \return pointer to category description
  960. */
  961. char *Rast_get_ith_f_cat(const struct Categories *pcats,
  962. int i, void *rast1, void *rast2)
  963. {
  964. RASTER_MAP_TYPE data_type = FCELL_TYPE;
  965. char *tmp;
  966. DCELL val1, val2;
  967. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  968. Rast_set_d_value(rast1, val1, data_type);
  969. Rast_set_d_value(rast2, val2, data_type);
  970. return tmp;
  971. }
  972. /*!
  973. * \brief Get category description (CELL)
  974. *
  975. * Returns i-th description and i-th data range from the list of
  976. * category descriptions with corresponding data ranges. end points of
  977. * data interval in <i>rast1</i> and <i>rast2</i>.
  978. *
  979. * \param pcats pointer to Categories structure
  980. * \param i index
  981. * \param rast1, rast2 raster values (range)
  982. *
  983. * \return "" on error
  984. * \return pointer to category description
  985. */
  986. char *Rast_get_ith_c_cat(const struct Categories *pcats,
  987. int i, void *rast1, void *rast2)
  988. {
  989. RASTER_MAP_TYPE data_type = CELL_TYPE;
  990. char *tmp;
  991. DCELL val1, val2;
  992. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  993. Rast_set_d_value(rast1, val1, data_type);
  994. Rast_set_d_value(rast2, val2, data_type);
  995. return tmp;
  996. }
  997. /*!
  998. * \brief Get category description
  999. *
  1000. * Returns i-th description and i-th data range from the list of
  1001. * category descriptions with corresponding data ranges. end points of
  1002. * data interval in <i>rast1</i> and <i>rast2</i>.
  1003. *
  1004. * \param pcats pointer to Categories structure
  1005. * \param i index
  1006. * \param rast1, rast2 raster values (range)
  1007. * \param data_type map type
  1008. *
  1009. * \return "" on error
  1010. * \return pointer to category description
  1011. */
  1012. char *Rast_get_ith_cat(const struct Categories *pcats, int i, void *rast1,
  1013. void *rast2, RASTER_MAP_TYPE data_type)
  1014. {
  1015. char *tmp;
  1016. DCELL val1, val2;
  1017. tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
  1018. Rast_set_d_value(rast1, val1, data_type);
  1019. Rast_set_d_value(rast2, val2, data_type);
  1020. return tmp;
  1021. }
  1022. /*!
  1023. * \brief Initialize category structure
  1024. *
  1025. * To construct a new category file, the structure must first be
  1026. * initialized. This routine initializes the <i>cats</i> structure,
  1027. * and copies the <i>title</i> into the structure. The number of
  1028. * categories is set initially to <i>n</i>.
  1029. *
  1030. * For example:
  1031. \code
  1032. struct Categories cats;
  1033. Rast_init_cats ("", &cats);
  1034. \endcode
  1035. *
  1036. * \todo Eliminate pcats->num. Num has no meaning in new Categories
  1037. * structure and only stores (int) largets data value for backwards
  1038. * compatibility.
  1039. *
  1040. * \param title title
  1041. * \param pcats pointer to Categories structure
  1042. */
  1043. void Rast_init_cats(const char *title, struct Categories *pcats)
  1044. {
  1045. Rast_set_cats_title(title, pcats);
  1046. pcats->labels = NULL;
  1047. pcats->nalloc = 0;
  1048. pcats->ncats = 0;
  1049. pcats->num = 0;
  1050. pcats->fmt = NULL;
  1051. pcats->m1 = 0.0;
  1052. pcats->a1 = 0.0;
  1053. pcats->m2 = 0.0;
  1054. pcats->a2 = 0.0;
  1055. pcats->last_marked_rule = -1;
  1056. Rast_quant_init(&pcats->q);
  1057. }
  1058. /*!
  1059. * \brief Set title in category structure
  1060. *
  1061. * \todo To be removed, replaced by Rast_set_cats_title().
  1062. *
  1063. * The <i>title</i> is copied into the <i>pcats</i> structure.
  1064. *
  1065. * \param title title
  1066. * \param pcats pointer to Categories structure
  1067. */
  1068. void Rast_set_cats_title(const char *title, struct Categories *pcats)
  1069. {
  1070. if (title == NULL)
  1071. title = "";
  1072. pcats->title = G_store(title);
  1073. G_newlines_to_spaces(pcats->title);
  1074. G_strip(pcats->title);
  1075. }
  1076. /*!
  1077. \brief Set category fmt (?)
  1078. \param fmt
  1079. \param m1
  1080. \param a1
  1081. \param m2
  1082. \param a2
  1083. \param pcats pointer to Categories structure
  1084. */
  1085. void Rast_set_cats_fmt(const char *fmt, double m1, double a1, double m2,
  1086. double a2, struct Categories *pcats)
  1087. {
  1088. pcats->m1 = m1;
  1089. pcats->a1 = a1;
  1090. pcats->m2 = m2;
  1091. pcats->a2 = a2;
  1092. pcats->fmt = G_store(fmt);
  1093. G_newlines_to_spaces(pcats->fmt);
  1094. G_strip(pcats->fmt);
  1095. }
  1096. /*!
  1097. * \brief Free category structure memory
  1098. *
  1099. * \todo To be removed, replaced by Rast_free_cats().
  1100. *
  1101. * Frees memory allocated by Rast_read_cats(), Rast_init_cats() and
  1102. * Rast_set_c_cat().
  1103. *
  1104. * \param pcats pointer to Categories structure
  1105. */
  1106. void Rast_free_cats(struct Categories *pcats)
  1107. {
  1108. int i;
  1109. if (pcats->title != NULL) {
  1110. G_free(pcats->title);
  1111. pcats->title = NULL;
  1112. }
  1113. if (pcats->fmt != NULL) {
  1114. G_free(pcats->fmt);
  1115. pcats->fmt = NULL;
  1116. }
  1117. if (pcats->ncats > 0) {
  1118. for (i = 0; i < pcats->ncats; i++)
  1119. if (pcats->labels[i] != NULL)
  1120. G_free(pcats->labels[i]);
  1121. G_free(pcats->labels);
  1122. G_free(pcats->marks);
  1123. pcats->labels = NULL;
  1124. }
  1125. Rast_quant_free(&pcats->q);
  1126. pcats->ncats = 0;
  1127. pcats->nalloc = 0;
  1128. }
  1129. /*!
  1130. * \brief Copy raster categories
  1131. *
  1132. * Allocates NEW space for quant rules and labels n <i>pcats_to</i>
  1133. * and copies all info from <i>pcats_from</i> cats to
  1134. * <i>pcats_to</i> cats.
  1135. *
  1136. * \param pcats_to pointer to destination Categories structure
  1137. * \param pcats_from pointer to source Categories structure
  1138. */
  1139. void Rast_copy_cats(struct Categories *pcats_to,
  1140. const struct Categories *pcats_from)
  1141. {
  1142. int i;
  1143. char *descr;
  1144. DCELL d1, d2;
  1145. Rast_init_cats(pcats_from->title, pcats_to);
  1146. for (i = 0; i < pcats_from->ncats; i++) {
  1147. descr = Rast_get_ith_d_cat(pcats_from, i, &d1, &d2);
  1148. Rast_set_d_cat(&d1, &d2, descr, pcats_to);
  1149. }
  1150. }
  1151. /*!
  1152. \brief Get number of raster categories
  1153. \param pcats pointer to Categories structure
  1154. \return number of categories
  1155. */
  1156. int Rast_number_of_cats(struct Categories *pcats)
  1157. {
  1158. return pcats->ncats;
  1159. }
  1160. /*!
  1161. \brief Sort categories
  1162. \param pcats pointer to Categories structure
  1163. \return -1 on error (nothing to sort)
  1164. \return 0 on success
  1165. */
  1166. int Rast_sort_cats(struct Categories *pcats)
  1167. {
  1168. int *indexes, i, ncats;
  1169. char *descr;
  1170. DCELL d1, d2;
  1171. if (pcats->ncats <= 1)
  1172. return -1;
  1173. ncats = pcats->ncats;
  1174. G_debug(3, "Rast_sort_cats(): Copying to save cats buffer");
  1175. Rast_copy_cats(&save_cats, pcats);
  1176. Rast_free_cats(pcats);
  1177. indexes = (int *)G_malloc(sizeof(int) * ncats);
  1178. for (i = 0; i < ncats; i++)
  1179. indexes[i] = i;
  1180. qsort(indexes, ncats, sizeof(int), cmp);
  1181. Rast_init_cats(save_cats.title, pcats);
  1182. for (i = 0; i < ncats; i++) {
  1183. descr = Rast_get_ith_d_cat(&save_cats, indexes[i], &d1, &d2);
  1184. G_debug(4, " Write sorted cats, pcats = %p pcats->labels = %p",
  1185. pcats, pcats->labels);
  1186. Rast_set_d_cat(&d1, &d2, descr, pcats);
  1187. }
  1188. Rast_free_cats(&save_cats);
  1189. return 0;
  1190. }
  1191. static int cmp(const void *aa, const void *bb)
  1192. {
  1193. const int *a = aa, *b = bb;
  1194. DCELL min_rast1, min_rast2, max_rast1, max_rast2;
  1195. CELL index;
  1196. Rast_quant_get_ith_rule(&(save_cats.q), *a,
  1197. &min_rast1, &max_rast1, &index, &index);
  1198. Rast_quant_get_ith_rule(&(save_cats.q), *b,
  1199. &min_rast2, &max_rast2, &index, &index);
  1200. if (min_rast1 < min_rast2)
  1201. return -1;
  1202. if (min_rast1 > min_rast2)
  1203. return 1;
  1204. return 0;
  1205. }