areas.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /*
  2. * Cell-file area extraction
  3. * Boundary tracing algorithm
  4. *
  5. * Jean Ezell
  6. * US Army Corps of Engineers
  7. * Construction Engineering Research Lab
  8. * Modelling and Simulation Team
  9. * Champaign, IL 61820
  10. * January 1988
  11. *
  12. * Fixed 3/2001 by Andrea Aime <aaime@comune.modena.it>
  13. * fixed area label problem with r.poly (it was creating more
  14. * labels than required if there were islands)
  15. *
  16. *************************
  17. * The algorithm allocates COOR structures as necessary to mark endpoints of
  18. * and bends in boundaries between areas. Each COOR structure contains the
  19. * row and column coordinates of a point which is either an endpoint or a
  20. * bend. If the point represents a bend, fptr and bptr point to the adjacent
  21. * endpoint(s) or bend(s); if an endpoint, one of fptr or bptr points to the
  22. * point itself and the other to the adjacent bend or endpoint. While a
  23. * boundary is under construction, fptr of the "free" end is NULL.
  24. * The right and left fields contain the area numbers to the right and
  25. * left of the line under construction. When two lines are joined, it
  26. * will be necessary to make the area numbers agree. This is done by mapping
  27. * one of the area numbers to another. The mapping is done in such a way
  28. * that the smallest number in each equivalence class is chosen to represent
  29. * the class. We also keep track of the longest horizontal strip in each
  30. * area. The left end of this strip will be used as the position of the
  31. * label in the dlg label file.
  32. *
  33. * Global variables:
  34. * v_list pointer to allocated array of pointers to endpoints of
  35. * vertical lines currently under construction
  36. * h_ptr pointer to endpoint of horizontal line currently
  37. * under construction
  38. * col, row column and row of current position in file
  39. * buffer[] pointers to the two allocated areas which hold the
  40. * two rows currently being processed
  41. * top, bottom which row of buffer[] is "top" line from file and
  42. * which is "bottom"
  43. * scan_length length of a row from the data file
  44. * tl, tr, bl, br top left and right, bottom left and right elements
  45. * in current 2 by 2 data window; one-time calculation
  46. * prevents multiple indexing and indirection
  47. * computations
  48. * a_list pointer to allocated array of correspondences between
  49. * areas and categories
  50. * n_areas current length of a_list
  51. * area_num lowest area number available for use
  52. * a_list_new pointer to next a_list entry to be used
  53. * a_list_old pointer to a_list entry just filled
  54. * e_list pointer to allocated array which is used to form
  55. * mapping of all equivalent area numbers onto one
  56. * number from the class
  57. * n_equiv current length of e_list
  58. *
  59. * Entry points:
  60. * extract_areas driver for boundary extraction, area labelling
  61. * algorithm
  62. * alloc_bufs allocate buffers for raster map data and storage of
  63. * information obtained in the extraction process (v_list,
  64. * a_list, e_list, buffer[0], buffer[1])
  65. *
  66. ********************************************************************/
  67. #include <stdio.h>
  68. #include <unistd.h>
  69. #include <grass/gis.h>
  70. #include <grass/raster.h>
  71. #include <grass/glocale.h>
  72. #include <grass/dbmi.h>
  73. #include "global.h"
  74. static int col, row, top, bottom;
  75. static double tl, tr, bl, br;
  76. static struct COOR **v_list;
  77. static struct COOR *h_ptr;
  78. static void *buffer[2];
  79. static int scan_length;
  80. static int n_areas, area_num, n_equiv, tl_area;
  81. static struct area_table *a_list, *a_list_new, *a_list_old;
  82. static struct equiv_table *e_list;
  83. /* function prototypes */
  84. static int update_list(int);
  85. static int end_vline();
  86. static int end_hline();
  87. static int start_vline();
  88. static int start_hline();
  89. static struct COOR *get_ptr();
  90. static int read_next();
  91. static int equiv_areas(int, int);
  92. static int map_area(int, int);
  93. static int add_to_list(int, int);
  94. static int assign_area(double, int);
  95. static int more_areas();
  96. static int update_width(struct area_table *, int);
  97. static int nabors(void);
  98. #define get_raster_value(ptr, col) \
  99. Rast_get_d_value(G_incr_void_ptr(ptr, (col)*data_size), data_type)
  100. /* extract_areas - trace boundaries of polygons in file */
  101. int extract_areas(void)
  102. {
  103. double nullVal;
  104. int i;
  105. row = col = top = 0; /* get started for read of first */
  106. bottom = 1; /* line from raster map */
  107. area_num = 0;
  108. tl_area = 0;
  109. n_alloced_ptrs = 0;
  110. Rast_set_d_null_value(&nullVal, 1);
  111. /* represents the "outside", the external null values */
  112. assign_area(nullVal, 0);
  113. G_message(_("Extracting areas..."));
  114. scan_length = read_next();
  115. while (read_next()) { /* read rest of file, one row at *//* a time */
  116. G_percent(row, n_rows + 1, 2);
  117. for (col = 0; col < scan_length - 1; col++) {
  118. tl = get_raster_value(buffer[top], col); /* top left in window */
  119. tr = get_raster_value(buffer[top], col + 1); /* top right */
  120. bl = get_raster_value(buffer[bottom], col); /* bottom left */
  121. br = get_raster_value(buffer[bottom], col + 1); /* bottom right */
  122. update_list(nabors());
  123. }
  124. if (h_ptr != NULPTR) /* if we have a loose end, */
  125. end_hline(); /* tie it down */
  126. row++;
  127. }
  128. G_percent(1, 1, 1);
  129. write_area(a_list, e_list, area_num, n_equiv);
  130. G_free(a_list);
  131. for (i = 0; i < n_equiv; i++) {
  132. if (e_list[i].ptr)
  133. G_free(e_list[i].ptr);
  134. }
  135. G_free(e_list);
  136. G_free(v_list);
  137. G_free(buffer[0]);
  138. G_free(buffer[1]);
  139. if (n_alloced_ptrs) {
  140. /* should not happen */
  141. G_warning("Memory leak: %d points are still in use", n_alloced_ptrs);
  142. }
  143. return 0;
  144. } /* extract_areas */
  145. /* update_list - maintains linked list of COOR structures which resprsent */
  146. /* bends in and endpoints of lines separating areas in input file; */
  147. /* compiles a list of area to category number correspondences; */
  148. /* for pictures of what each case in the switch represents, see comments */
  149. /* before nabors() */
  150. static int update_list(int i)
  151. {
  152. struct COOR *new_ptr, *new_ptr1, *new_ptr2, *new_ptr3;
  153. double right, left;
  154. switch (i) {
  155. case 0:
  156. /* Vertical line - Just update width information */
  157. /* update_width(a_list + v_list[col]->left,0); */
  158. tl_area = v_list[col]->left;
  159. break;
  160. case 1:
  161. /* Bottom right corner - Point in middle of new line */
  162. /* (growing) <- ptr2 -><- ptr1 -><- ptr3 -> (growing) */
  163. /* (?, col) (row, col) (row, ?) */
  164. new_ptr1 = get_ptr(); /* corner point */
  165. new_ptr2 = get_ptr(); /* downward-growing point */
  166. new_ptr3 = get_ptr(); /* right-growing point */
  167. new_ptr1->bptr = new_ptr2;
  168. new_ptr1->fptr = new_ptr3;
  169. new_ptr2->bptr = new_ptr3->bptr = new_ptr1;
  170. /* if(Rast_is_c_null_value(&tl_area)) {
  171. new_ptr1->left = new_ptr2->right = new_ptr3->left = 0;
  172. assign_area(tl,1);
  173. } else {
  174. */
  175. new_ptr1->left = new_ptr2->right = new_ptr3->left = tl_area;
  176. new_ptr1->right = new_ptr2->left = new_ptr3->right = area_num;
  177. assign_area(br, 1);
  178. update_width(a_list_old, 1);
  179. v_list[col] = new_ptr2;
  180. h_ptr = new_ptr3;
  181. break;
  182. case 3:
  183. /* Bottom left corner - Add point to line already under construction */
  184. /* (fixed) -><- original h_ptr -><- new_ptr -> (growing) */
  185. /* (row, col) (?, col) */
  186. tl_area = h_ptr->left;
  187. new_ptr = get_ptr(); /* downward-growing point */
  188. h_ptr->col = col;
  189. h_ptr->fptr = new_ptr;
  190. new_ptr->bptr = h_ptr;
  191. new_ptr->left = h_ptr->left;
  192. new_ptr->right = h_ptr->right;
  193. /* update_width(a_list + new_ptr->left,3); */
  194. v_list[col] = new_ptr;
  195. h_ptr = NULPTR;
  196. break;
  197. case 4:
  198. /* Top left corner - Join two lines already under construction */
  199. /* (fixed) -><- original v_list -><- (fixed) */
  200. /* (row, col) */
  201. tl_area = v_list[col]->left;
  202. equiv_areas(h_ptr->left, v_list[col]->right);
  203. equiv_areas(h_ptr->right, v_list[col]->left);
  204. v_list[col]->row = row; /* keep downward-growing point */
  205. v_list[col]->fptr = h_ptr->bptr; /* and join it to predecessor */
  206. h_ptr->bptr->fptr = v_list[col]; /* of right-growing point */
  207. free_ptr(h_ptr); /* right-growing point disappears */
  208. h_ptr = NULPTR; /* turn loose of pointers */
  209. write_boundary(v_list[col]); /* try to write line */
  210. v_list[col] = NULPTR; /* turn loose of pointers */
  211. break;
  212. case 5:
  213. /* Top right corner - Add point to line already under construction */
  214. /* (fixed) -><- original v_list -><- new_ptr -> (growing) */
  215. /* (row, col) (row, ?) */
  216. new_ptr = get_ptr(); /* right-growing point */
  217. v_list[col]->row = row;
  218. new_ptr->bptr = v_list[col];
  219. new_ptr->left = v_list[col]->left;
  220. new_ptr->right = v_list[col]->right;
  221. v_list[col]->fptr = new_ptr;
  222. h_ptr = new_ptr;
  223. v_list[col] = NULPTR;
  224. break;
  225. case 6:
  226. /* T upward - End one vertical and one horizontal line */
  227. /* Start horizontal line */
  228. v_list[col]->node = h_ptr->node = 1;
  229. left = v_list[col]->left;
  230. right = h_ptr->right;
  231. end_vline();
  232. end_hline();
  233. start_hline();
  234. h_ptr->bptr->node = 1; /* where we came from is a node */
  235. h_ptr->left = h_ptr->bptr->left = left;
  236. h_ptr->right = h_ptr->bptr->right = right;
  237. break;
  238. case 7:
  239. /* T downward - End horizontal line */
  240. /* Start one vertical and one horizontal line */
  241. h_ptr->node = 1;
  242. right = h_ptr->right;
  243. left = h_ptr->left;
  244. end_hline();
  245. start_hline();
  246. start_vline();
  247. h_ptr->bptr->node = v_list[col]->bptr->node = 1;
  248. h_ptr->left = h_ptr->bptr->left = left;
  249. h_ptr->right = h_ptr->bptr->right = v_list[col]->left =
  250. v_list[col]->bptr->left = area_num;
  251. assign_area(br, 7);
  252. update_width(a_list_old, 7);
  253. v_list[col]->right = v_list[col]->bptr->right = right;
  254. break;
  255. case 8:
  256. /* T left - End one vertical and one horizontal line */
  257. /* Start one vertical line */
  258. tl_area = v_list[col]->left;
  259. h_ptr->node = v_list[col]->node = 1;
  260. right = h_ptr->right;
  261. left = v_list[col]->left;
  262. end_vline();
  263. end_hline();
  264. start_vline();
  265. v_list[col]->bptr->node = 1; /* where we came from is a node */
  266. v_list[col]->left = v_list[col]->bptr->left = left;
  267. v_list[col]->right = v_list[col]->bptr->right = right;
  268. /* update_width(a_list + v_list[col]->left,8); */
  269. break;
  270. case 9:
  271. /* T right - End one vertical line */
  272. /* Start one vertical and one horizontal line */
  273. v_list[col]->node = 1;
  274. right = v_list[col]->right;
  275. left = v_list[col]->left;
  276. end_vline();
  277. start_vline();
  278. start_hline();
  279. v_list[col]->bptr->node = h_ptr->bptr->node = 1;
  280. h_ptr->left = h_ptr->bptr->left = left;
  281. h_ptr->right = h_ptr->bptr->right = v_list[col]->left =
  282. v_list[col]->bptr->left = area_num;
  283. assign_area(br, 9);
  284. update_width(a_list_old, 9);
  285. v_list[col]->right = v_list[col]->bptr->right = right;
  286. break;
  287. case 10:
  288. /* Cross - End one vertical and one horizontal line */
  289. /* Start one vertical and one horizontal line */
  290. v_list[col]->node = h_ptr->node = 1;
  291. left = v_list[col]->left;
  292. right = h_ptr->right;
  293. end_vline();
  294. end_hline();
  295. start_vline();
  296. start_hline();
  297. v_list[col]->bptr->node = h_ptr->bptr->node = 1;
  298. h_ptr->left = h_ptr->bptr->left = left;
  299. v_list[col]->left = v_list[col]->bptr->left = h_ptr->right =
  300. h_ptr->bptr->right = area_num;
  301. assign_area(br, 10);
  302. update_width(a_list_old, 10);
  303. v_list[col]->right = v_list[col]->bptr->right = right;
  304. break;
  305. } /* switch */
  306. return 0;
  307. } /* update_list */
  308. /* end_vline, end_hline - end vertical or horizontal line and try */
  309. /* to write it out */
  310. static int end_vline(void)
  311. {
  312. v_list[col]->row = row;
  313. v_list[col]->fptr = v_list[col];
  314. write_boundary(v_list[col]);
  315. v_list[col] = NULPTR;
  316. return 0;
  317. }
  318. static int end_hline(void)
  319. {
  320. h_ptr->col = col;
  321. h_ptr->fptr = h_ptr;
  322. write_boundary(h_ptr);
  323. h_ptr = NULPTR;
  324. return 0;
  325. }
  326. /* start_vline, start_hline - begin line in vertical or horizontal */
  327. /* direction */
  328. static int start_vline(void)
  329. {
  330. struct COOR *new_ptr1, *new_ptr2;
  331. new_ptr1 = get_ptr();
  332. new_ptr2 = get_ptr();
  333. new_ptr1->fptr = new_ptr2;
  334. new_ptr2->bptr = new_ptr1->bptr = new_ptr1;
  335. new_ptr2->fptr = NULPTR;
  336. v_list[col] = new_ptr2;
  337. return 0;
  338. }
  339. static int start_hline(void)
  340. {
  341. struct COOR *new_ptr1, *new_ptr2;
  342. new_ptr1 = get_ptr();
  343. new_ptr2 = get_ptr();
  344. new_ptr1->bptr = new_ptr2->bptr = new_ptr1;
  345. new_ptr1->fptr = new_ptr2;
  346. new_ptr2->fptr = NULPTR;
  347. h_ptr = new_ptr2;
  348. return 0;
  349. }
  350. /* get_ptr - allocate storage for yet another COOR structure */
  351. static struct COOR *get_ptr(void)
  352. {
  353. static struct COOR *ptr;
  354. ptr = (struct COOR *)G_malloc(sizeof(struct COOR));
  355. ptr->row = row;
  356. ptr->col = col;
  357. ptr->fptr = ptr->bptr = NULPTR;
  358. ptr->node = ptr->left = ptr->right = 0;
  359. n_alloced_ptrs++;
  360. return (ptr);
  361. }
  362. /* nabors - check 2 x 2 matrix and return case from table below */
  363. /* *--*--* *--*--* *--*--* *--*--* */
  364. /* | | | | | | | | | */
  365. /* * | * * *--* *-----* *--* * */
  366. /* | | | | | | | | | | | */
  367. /* *--*--* *--*--* *--*--* *--*--* */
  368. /* 0 1 2 3 */
  369. /* *--*--* *--*--* *--*--* *--*--* */
  370. /* | | | | | | | | | | | */
  371. /* *--* * * *--* *--*--* *--*--* */
  372. /* | | | | | | | | | */
  373. /* *--*--* *--*--* *--*--* *--*--* */
  374. /* 4 5 6 7 */
  375. /* *--*--* *--*--* *--*--* *--*--* */
  376. /* | | | | | | | | | | | */
  377. /* *--* * * *--* *--*--* * * */
  378. /* | | | | | | | | | | | */
  379. /* *--*--* *--*--* *--*--* *--*--* */
  380. /* */
  381. /* 8 9 10 11 */
  382. static int nabors(void)
  383. {
  384. int tl_null = Rast_is_d_null_value(&tl);
  385. int tr_null = Rast_is_d_null_value(&tr);
  386. int bl_null = Rast_is_d_null_value(&bl);
  387. int br_null = Rast_is_d_null_value(&br);
  388. /* if both a and b are NULLs, thery are equal */
  389. #define cmp(a, b) (a##_null+b##_null==1 || (a##_null+b##_null==0 && a != b))
  390. if (cmp(tl, tr) != 0) { /* 0, 4, 5, 6, 8, 9, 10 */
  391. if (cmp(tl, bl) != 0) { /* 4, 6, 8, 10 */
  392. if (cmp(bl, br) != 0) { /* 8, 10 */
  393. if (cmp(tr, br) != 0)
  394. return (10);
  395. else
  396. return (8);
  397. }
  398. else { /* 4, 6 */
  399. if (cmp(tr, br) != 0)
  400. return (6);
  401. else
  402. return (4);
  403. }
  404. }
  405. else { /* 0, 5, 9 */
  406. if (cmp(bl, br) != 0) { /* 0, 9 */
  407. if (cmp(tr, br) != 0)
  408. return (9);
  409. else
  410. return (0);
  411. }
  412. else
  413. return (5);
  414. }
  415. }
  416. else { /* 1, 2, 3, 7, 11 */
  417. if (cmp(tl, bl) != 0) { /* 2, 3, 7 */
  418. if (cmp(bl, br) != 0) { /* 3, 7 */
  419. if (cmp(tr, br) != 0)
  420. return (7);
  421. else
  422. return (3);
  423. }
  424. else
  425. return (2);
  426. }
  427. else { /* 1, 11 */
  428. if (cmp(bl, br) != 0)
  429. return (1);
  430. else
  431. return (11);
  432. }
  433. }
  434. return 0;
  435. }
  436. /* read_next - read another line from input file */
  437. static int read_next(void)
  438. {
  439. int n;
  440. top = bottom++; /* switch top and bottom, */
  441. bottom = 1 & bottom; /* which are always 0 or 1 */
  442. n = read_row(buffer[bottom]);
  443. return (n);
  444. }
  445. /* alloc_bufs - allocate buffers we will need for storing raster map */
  446. /* data, pointers to extracted lines, area number information */
  447. int alloc_areas_bufs(int size)
  448. {
  449. int i;
  450. buffer[0] = (void *)G_malloc(size * data_size);
  451. buffer[1] = (void *)G_malloc(size * data_size);
  452. v_list = (struct COOR **)G_malloc(size * sizeof(*v_list));
  453. n_areas = n_equiv = 500; /* guess at number of areas, equivs */
  454. a_list =
  455. (struct area_table *)G_malloc(n_areas * sizeof(struct area_table));
  456. for (i = 0; i < n_areas; i++) {
  457. (a_list + i)->width = (a_list + i)->row = (a_list + i)->col = 0;
  458. (a_list + i)->free = 1;
  459. }
  460. a_list_new = a_list_old = a_list;
  461. e_list =
  462. (struct equiv_table *)G_malloc(n_equiv * sizeof(struct equiv_table));
  463. for (i = 0; i < n_equiv; i++) {
  464. (e_list + i)->mapped = (e_list + i)->count = 0;
  465. (e_list + i)->ptr = NULL;
  466. }
  467. return 0;
  468. }
  469. /* equiv_areas - force two areas to be equivalent and generate */
  470. /* mapping information */
  471. static int equiv_areas(int a1, int a2)
  472. {
  473. int small, large, small_obj, large_obj;
  474. if (a1 == -1 || a2 == -2)
  475. return 0;
  476. if (a1 == a2)
  477. return (0);
  478. if (a1 < a2) {
  479. small = a1;
  480. large = a2;
  481. }
  482. else {
  483. small = a2;
  484. large = a1;
  485. }
  486. while (large >= n_equiv) /* make sure our equivalence tables */
  487. more_equivs(); /* are large enough */
  488. if ((e_list + large)->mapped) {
  489. if ((e_list + small)->mapped) { /* small mapped, large mapped */
  490. large_obj = (e_list + large)->where;
  491. small_obj = (e_list + small)->where;
  492. if (large_obj == small_obj) /* both mapped to same place */
  493. return (0);
  494. if (small_obj < large_obj) /* map where large goes to where */
  495. map_area(large_obj, small_obj); /* small goes */
  496. else /* map where small goes to where */
  497. map_area(small_obj, large_obj); /* large goes */
  498. }
  499. else { /* small not mapped, large mapped */
  500. large_obj = (e_list + large)->where;
  501. if (small == large_obj) /* large already mapped to small */
  502. return (0);
  503. if (small < large_obj) /* map where large goes to small */
  504. map_area(large_obj, small);
  505. else /* map small to where large goes */
  506. map_area(small, large_obj);
  507. }
  508. }
  509. else {
  510. if ((e_list + small)->mapped) /* small mapped, large not mapped */
  511. map_area(large, (e_list + small)->where);
  512. else /* small not mapped, large not mapped */
  513. map_area(large, small);
  514. }
  515. return (0);
  516. }
  517. /* map_area - establish a mapping from one area to another */
  518. /* the area number mapping looks like the following: */
  519. /* area numbers index into e_list to get equiv_table structures */
  520. /* for each of these structures, */
  521. /* .mapped indicates whether area number is mapped */
  522. /* if area number is mapped */
  523. /* .where tells to what other area number */
  524. /* if area number is not mapped */
  525. /* .count tells how many areas are mapped to this one */
  526. /* if count != 0 */
  527. /* .ptr gives a pointer to the list of area numbers */
  528. static int map_area(int x, int y /* map x to y */
  529. )
  530. {
  531. int n, i, *p;
  532. (e_list + x)->mapped = 1;
  533. (e_list + x)->where = y;
  534. if ((a_list + x)->width > (a_list + y)->width) {
  535. (a_list + y)->width = (a_list + x)->width;
  536. (a_list + y)->row = (a_list + x)->row;
  537. (a_list + y)->col = (a_list + x)->col;
  538. }
  539. if (add_to_list(x, y)) { /* if x is not already in y's list */
  540. n = (e_list + x)->count;
  541. p = (e_list + x)->ptr;
  542. for (i = 0; i < n; i++) { /* map everything that is currently *//* mapped onto x onto y; because */
  543. (e_list + *p)->where = y; /* of this reshuffle, only one */
  544. add_to_list(*p++, y); /* level of mapping is ever needed */
  545. }
  546. }
  547. return 0;
  548. }
  549. /* add_to_list - add another area number to an equivalence list */
  550. static int add_to_list(int x, int y)
  551. {
  552. int n, i;
  553. struct equiv_table *e_list_y;
  554. e_list_y = e_list + y;
  555. n = e_list_y->count;
  556. if (n == 0) { /* first time through--start list */
  557. e_list_y->length = 20; /* initial guess at storage needed */
  558. e_list_y->ptr = (int *)G_malloc(e_list_y->length * sizeof(int));
  559. *(e_list_y->ptr) = x;
  560. (e_list_y->count)++;
  561. }
  562. else { /* list already started */
  563. for (i = 0; i < n; i++) { /* check whether x is already *//* in list */
  564. if (*(e_list_y->ptr + i) == x)
  565. return (0); /* if so, we don't need to add it */
  566. }
  567. if (n + 1 >= e_list_y->length) { /* add more space for storage *//* if necessary */
  568. e_list_y->length += 10;
  569. e_list_y->ptr =
  570. (int *)G_realloc(e_list_y->ptr,
  571. e_list_y->length * sizeof(int));
  572. }
  573. *(e_list_y->ptr + n) = x; /* add x to list */
  574. (e_list_y->count)++;
  575. }
  576. return (1); /* indicate addition made */
  577. }
  578. /* assign_area - make current area number correspond to the passed */
  579. /* category number and allocate more space to store areas if necessary */
  580. static int assign_area(double cat, int kase)
  581. {
  582. a_list_new->free = 0;
  583. a_list_new->cat = cat;
  584. area_num++;
  585. if (area_num >= n_areas)
  586. more_areas();
  587. a_list_old = a_list + area_num - 1;
  588. a_list_new = a_list + area_num;
  589. return 0;
  590. }
  591. /* more_areas - allocate larger space to store area correspondences */
  592. static int more_areas(void)
  593. {
  594. int old_n, i;
  595. old_n = n_areas;
  596. n_areas += 250;
  597. a_list =
  598. (struct area_table *)G_realloc(a_list,
  599. n_areas * sizeof(struct area_table));
  600. for (i = old_n; i < n_areas; i++) {
  601. (a_list + i)->width = -1;
  602. (a_list + i)->free = 1;
  603. }
  604. return 0;
  605. }
  606. /* more_equivs - allocate more space to construct equivalence information */
  607. int more_equivs(void)
  608. {
  609. int old_n, i;
  610. old_n = n_equiv;
  611. n_equiv += 250;
  612. e_list =
  613. (struct equiv_table *)G_realloc(e_list,
  614. n_equiv * sizeof(struct equiv_table));
  615. for (i = old_n; i < n_equiv; i++) {
  616. (e_list + i)->mapped = (e_list + i)->count = 0;
  617. (e_list + i)->ptr = NULL;
  618. }
  619. return 0;
  620. }
  621. /* update_width - update position of longest horizontal strip in an area */
  622. static int update_width(struct area_table *ptr, int kase)
  623. {
  624. int w, j, a;
  625. struct equiv_table *ep;
  626. a = (ptr - a_list);
  627. for (j = col + 1, w = 0; j < scan_length &&
  628. get_raster_value(buffer[bottom], j) == br; j++, w++) ;
  629. if (a == 0)
  630. G_debug(1, "Area 0, %d \t%d \t%d \t%d \t%d", kase, row, col,
  631. ptr->width, w);
  632. if (a < n_equiv) {
  633. ep = e_list + a;
  634. if (ep->mapped)
  635. ptr = a_list + ep->where;
  636. }
  637. if (w > ptr->width) {
  638. ptr->width = w;
  639. ptr->row = row;
  640. ptr->col = col;
  641. }
  642. return 0;
  643. }