123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751 |
- /*
- * Cell-file area extraction
- * Boundary tracing algorithm
- *
- * Jean Ezell
- * US Army Corps of Engineers
- * Construction Engineering Research Lab
- * Modelling and Simulation Team
- * Champaign, IL 61820
- * January 1988
- *
- * Fixed 3/2001 by Andrea Aime <aaime@comune.modena.it>
- * fixed area label problem with r.poly (it was creating more
- * labels than required if there were islands)
- *
- *************************
- * The algorithm allocates COOR structures as necessary to mark endpoints of
- * and bends in boundaries between areas. Each COOR structure contains the
- * row and column coordinates of a point which is either an endpoint or a
- * bend. If the point represents a bend, fptr and bptr point to the adjacent
- * endpoint(s) or bend(s); if an endpoint, one of fptr or bptr points to the
- * point itself and the other to the adjacent bend or endpoint. While a
- * boundary is under construction, fptr of the "free" end is NULL.
- * The right and left fields contain the area numbers to the right and
- * left of the line under construction. When two lines are joined, it
- * will be necessary to make the area numbers agree. This is done by mapping
- * one of the area numbers to another. The mapping is done in such a way
- * that the smallest number in each equivalence class is chosen to represent
- * the class. We also keep track of the longest horizontal strip in each
- * area. The left end of this strip will be used as the position of the
- * label in the dlg label file.
- *
- * Global variables:
- * v_list pointer to allocated array of pointers to endpoints of
- * vertical lines currently under construction
- * h_ptr pointer to endpoint of horizontal line currently
- * under construction
- * col, row column and row of current position in file
- * buffer[] pointers to the two allocated areas which hold the
- * two rows currently being processed
- * top, bottom which row of buffer[] is "top" line from file and
- * which is "bottom"
- * scan_length length of a row from the data file
- * tl, tr, bl, br top left and right, bottom left and right elements
- * in current 2 by 2 data window; one-time calculation
- * prevents multiple indexing and indirection
- * computations
- * a_list pointer to allocated array of correspondences between
- * areas and categories
- * n_areas current length of a_list
- * area_num lowest area number available for use
- * a_list_new pointer to next a_list entry to be used
- * a_list_old pointer to a_list entry just filled
- * e_list pointer to allocated array which is used to form
- * mapping of all equivalent area numbers onto one
- * number from the class
- * n_equiv current length of e_list
- *
- * Entry points:
- * extract_areas driver for boundary extraction, area labelling
- * algorithm
- * alloc_bufs allocate buffers for raster map data and storage of
- * information obtained in the extraction process (v_list,
- * a_list, e_list, buffer[0], buffer[1])
- *
- ********************************************************************/
- #include <stdio.h>
- #include <unistd.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #include <grass/dbmi.h>
- #include "global.h"
- static int col, row, top, bottom;
- static double tl, tr, bl, br;
- static struct COOR **v_list;
- static struct COOR *h_ptr;
- static void *buffer[2];
- static int scan_length;
- static int n_areas, area_num, n_equiv, tl_area;
- static struct area_table *a_list, *a_list_new, *a_list_old;
- static struct equiv_table *e_list;
- /* function prototypes */
- static int update_list(int);
- static int end_vline();
- static int end_hline();
- static int start_vline();
- static int start_hline();
- static struct COOR *get_ptr();
- static int read_next();
- static int equiv_areas(int, int);
- static int map_area(int, int);
- static int add_to_list(int, int);
- static int assign_area(double, int);
- static int more_areas();
- static int update_width(struct area_table *, int);
- static int nabors(void);
- #define get_raster_value(ptr, col) \
- Rast_get_d_value(G_incr_void_ptr(ptr, (col)*data_size), data_type)
- /* extract_areas - trace boundaries of polygons in file */
- int extract_areas(void)
- {
- double nullVal;
- int i;
- row = col = top = 0; /* get started for read of first */
- bottom = 1; /* line from raster map */
- area_num = 0;
- tl_area = 0;
- n_alloced_ptrs = 0;
- Rast_set_d_null_value(&nullVal, 1);
- /* represents the "outside", the external null values */
- assign_area(nullVal, 0);
- G_message(_("Extracting areas..."));
- scan_length = read_next();
- while (read_next()) { /* read rest of file, one row at *//* a time */
- G_percent(row, n_rows + 1, 2);
- for (col = 0; col < scan_length - 1; col++) {
- tl = get_raster_value(buffer[top], col); /* top left in window */
- tr = get_raster_value(buffer[top], col + 1); /* top right */
- bl = get_raster_value(buffer[bottom], col); /* bottom left */
- br = get_raster_value(buffer[bottom], col + 1); /* bottom right */
- update_list(nabors());
- }
- if (h_ptr != NULPTR) /* if we have a loose end, */
- end_hline(); /* tie it down */
- row++;
- }
- G_percent(1, 1, 1);
- write_area(a_list, e_list, area_num, n_equiv);
- G_free(a_list);
- for (i = 0; i < n_equiv; i++) {
- if (e_list[i].ptr)
- G_free(e_list[i].ptr);
- }
- G_free(e_list);
- G_free(v_list);
- G_free(buffer[0]);
- G_free(buffer[1]);
- if (n_alloced_ptrs) {
- /* should not happen */
- G_warning("Memory leak: %d points are still in use", n_alloced_ptrs);
- }
- return 0;
- } /* extract_areas */
- /* update_list - maintains linked list of COOR structures which resprsent */
- /* bends in and endpoints of lines separating areas in input file; */
- /* compiles a list of area to category number correspondences; */
- /* for pictures of what each case in the switch represents, see comments */
- /* before nabors() */
- static int update_list(int i)
- {
- struct COOR *new_ptr, *new_ptr1, *new_ptr2, *new_ptr3;
- double right, left;
- switch (i) {
- case 0:
- /* Vertical line - Just update width information */
- /* update_width(a_list + v_list[col]->left,0); */
- tl_area = v_list[col]->left;
- break;
- case 1:
- /* Bottom right corner - Point in middle of new line */
- /* (growing) <- ptr2 -><- ptr1 -><- ptr3 -> (growing) */
- /* (?, col) (row, col) (row, ?) */
- new_ptr1 = get_ptr(); /* corner point */
- new_ptr2 = get_ptr(); /* downward-growing point */
- new_ptr3 = get_ptr(); /* right-growing point */
- new_ptr1->bptr = new_ptr2;
- new_ptr1->fptr = new_ptr3;
- new_ptr2->bptr = new_ptr3->bptr = new_ptr1;
- /* if(Rast_is_c_null_value(&tl_area)) {
- new_ptr1->left = new_ptr2->right = new_ptr3->left = 0;
- assign_area(tl,1);
- } else {
- */
- new_ptr1->left = new_ptr2->right = new_ptr3->left = tl_area;
- new_ptr1->right = new_ptr2->left = new_ptr3->right = area_num;
- assign_area(br, 1);
- update_width(a_list_old, 1);
- v_list[col] = new_ptr2;
- h_ptr = new_ptr3;
- break;
- case 3:
- /* Bottom left corner - Add point to line already under construction */
- /* (fixed) -><- original h_ptr -><- new_ptr -> (growing) */
- /* (row, col) (?, col) */
- tl_area = h_ptr->left;
- new_ptr = get_ptr(); /* downward-growing point */
- h_ptr->col = col;
- h_ptr->fptr = new_ptr;
- new_ptr->bptr = h_ptr;
- new_ptr->left = h_ptr->left;
- new_ptr->right = h_ptr->right;
- /* update_width(a_list + new_ptr->left,3); */
- v_list[col] = new_ptr;
- h_ptr = NULPTR;
- break;
- case 4:
- /* Top left corner - Join two lines already under construction */
- /* (fixed) -><- original v_list -><- (fixed) */
- /* (row, col) */
- tl_area = v_list[col]->left;
- equiv_areas(h_ptr->left, v_list[col]->right);
- equiv_areas(h_ptr->right, v_list[col]->left);
- v_list[col]->row = row; /* keep downward-growing point */
- v_list[col]->fptr = h_ptr->bptr; /* and join it to predecessor */
- h_ptr->bptr->fptr = v_list[col]; /* of right-growing point */
- free_ptr(h_ptr); /* right-growing point disappears */
- h_ptr = NULPTR; /* turn loose of pointers */
- write_boundary(v_list[col]); /* try to write line */
- v_list[col] = NULPTR; /* turn loose of pointers */
- break;
- case 5:
- /* Top right corner - Add point to line already under construction */
- /* (fixed) -><- original v_list -><- new_ptr -> (growing) */
- /* (row, col) (row, ?) */
- new_ptr = get_ptr(); /* right-growing point */
- v_list[col]->row = row;
- new_ptr->bptr = v_list[col];
- new_ptr->left = v_list[col]->left;
- new_ptr->right = v_list[col]->right;
- v_list[col]->fptr = new_ptr;
- h_ptr = new_ptr;
- v_list[col] = NULPTR;
- break;
- case 6:
- /* T upward - End one vertical and one horizontal line */
- /* Start horizontal line */
- v_list[col]->node = h_ptr->node = 1;
- left = v_list[col]->left;
- right = h_ptr->right;
- end_vline();
- end_hline();
- start_hline();
- h_ptr->bptr->node = 1; /* where we came from is a node */
- h_ptr->left = h_ptr->bptr->left = left;
- h_ptr->right = h_ptr->bptr->right = right;
- break;
- case 7:
- /* T downward - End horizontal line */
- /* Start one vertical and one horizontal line */
- h_ptr->node = 1;
- right = h_ptr->right;
- left = h_ptr->left;
- end_hline();
- start_hline();
- start_vline();
- h_ptr->bptr->node = v_list[col]->bptr->node = 1;
- h_ptr->left = h_ptr->bptr->left = left;
- h_ptr->right = h_ptr->bptr->right = v_list[col]->left =
- v_list[col]->bptr->left = area_num;
- assign_area(br, 7);
- update_width(a_list_old, 7);
- v_list[col]->right = v_list[col]->bptr->right = right;
- break;
- case 8:
- /* T left - End one vertical and one horizontal line */
- /* Start one vertical line */
- tl_area = v_list[col]->left;
- h_ptr->node = v_list[col]->node = 1;
- right = h_ptr->right;
- left = v_list[col]->left;
- end_vline();
- end_hline();
- start_vline();
- v_list[col]->bptr->node = 1; /* where we came from is a node */
- v_list[col]->left = v_list[col]->bptr->left = left;
- v_list[col]->right = v_list[col]->bptr->right = right;
- /* update_width(a_list + v_list[col]->left,8); */
- break;
- case 9:
- /* T right - End one vertical line */
- /* Start one vertical and one horizontal line */
- v_list[col]->node = 1;
- right = v_list[col]->right;
- left = v_list[col]->left;
- end_vline();
- start_vline();
- start_hline();
- v_list[col]->bptr->node = h_ptr->bptr->node = 1;
- h_ptr->left = h_ptr->bptr->left = left;
- h_ptr->right = h_ptr->bptr->right = v_list[col]->left =
- v_list[col]->bptr->left = area_num;
- assign_area(br, 9);
- update_width(a_list_old, 9);
- v_list[col]->right = v_list[col]->bptr->right = right;
- break;
- case 10:
- /* Cross - End one vertical and one horizontal line */
- /* Start one vertical and one horizontal line */
- v_list[col]->node = h_ptr->node = 1;
- left = v_list[col]->left;
- right = h_ptr->right;
- end_vline();
- end_hline();
- start_vline();
- start_hline();
- v_list[col]->bptr->node = h_ptr->bptr->node = 1;
- h_ptr->left = h_ptr->bptr->left = left;
- v_list[col]->left = v_list[col]->bptr->left = h_ptr->right =
- h_ptr->bptr->right = area_num;
- assign_area(br, 10);
- update_width(a_list_old, 10);
- v_list[col]->right = v_list[col]->bptr->right = right;
- break;
- } /* switch */
- return 0;
- } /* update_list */
- /* end_vline, end_hline - end vertical or horizontal line and try */
- /* to write it out */
- static int end_vline(void)
- {
- v_list[col]->row = row;
- v_list[col]->fptr = v_list[col];
- write_boundary(v_list[col]);
- v_list[col] = NULPTR;
- return 0;
- }
- static int end_hline(void)
- {
- h_ptr->col = col;
- h_ptr->fptr = h_ptr;
- write_boundary(h_ptr);
- h_ptr = NULPTR;
- return 0;
- }
- /* start_vline, start_hline - begin line in vertical or horizontal */
- /* direction */
- static int start_vline(void)
- {
- struct COOR *new_ptr1, *new_ptr2;
- new_ptr1 = get_ptr();
- new_ptr2 = get_ptr();
- new_ptr1->fptr = new_ptr2;
- new_ptr2->bptr = new_ptr1->bptr = new_ptr1;
- new_ptr2->fptr = NULPTR;
- v_list[col] = new_ptr2;
- return 0;
- }
- static int start_hline(void)
- {
- struct COOR *new_ptr1, *new_ptr2;
- new_ptr1 = get_ptr();
- new_ptr2 = get_ptr();
- new_ptr1->bptr = new_ptr2->bptr = new_ptr1;
- new_ptr1->fptr = new_ptr2;
- new_ptr2->fptr = NULPTR;
- h_ptr = new_ptr2;
- return 0;
- }
- /* get_ptr - allocate storage for yet another COOR structure */
- static struct COOR *get_ptr(void)
- {
- static struct COOR *ptr;
- ptr = (struct COOR *)G_malloc(sizeof(struct COOR));
- ptr->row = row;
- ptr->col = col;
- ptr->fptr = ptr->bptr = NULPTR;
- ptr->node = ptr->left = ptr->right = 0;
-
- n_alloced_ptrs++;
- return (ptr);
- }
- /* nabors - check 2 x 2 matrix and return case from table below */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* | | | | | | | | | */
- /* * | * * *--* *-----* *--* * */
- /* | | | | | | | | | | | */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* 0 1 2 3 */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* | | | | | | | | | | | */
- /* *--* * * *--* *--*--* *--*--* */
- /* | | | | | | | | | */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* 4 5 6 7 */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* | | | | | | | | | | | */
- /* *--* * * *--* *--*--* * * */
- /* | | | | | | | | | | | */
- /* *--*--* *--*--* *--*--* *--*--* */
- /* */
- /* 8 9 10 11 */
- static int nabors(void)
- {
- int tl_null = Rast_is_d_null_value(&tl);
- int tr_null = Rast_is_d_null_value(&tr);
- int bl_null = Rast_is_d_null_value(&bl);
- int br_null = Rast_is_d_null_value(&br);
- /* if both a and b are NULLs, thery are equal */
- #define cmp(a, b) (a##_null+b##_null==1 || (a##_null+b##_null==0 && a != b))
- if (cmp(tl, tr) != 0) { /* 0, 4, 5, 6, 8, 9, 10 */
- if (cmp(tl, bl) != 0) { /* 4, 6, 8, 10 */
- if (cmp(bl, br) != 0) { /* 8, 10 */
- if (cmp(tr, br) != 0)
- return (10);
- else
- return (8);
- }
- else { /* 4, 6 */
- if (cmp(tr, br) != 0)
- return (6);
- else
- return (4);
- }
- }
- else { /* 0, 5, 9 */
- if (cmp(bl, br) != 0) { /* 0, 9 */
- if (cmp(tr, br) != 0)
- return (9);
- else
- return (0);
- }
- else
- return (5);
- }
- }
- else { /* 1, 2, 3, 7, 11 */
- if (cmp(tl, bl) != 0) { /* 2, 3, 7 */
- if (cmp(bl, br) != 0) { /* 3, 7 */
- if (cmp(tr, br) != 0)
- return (7);
- else
- return (3);
- }
- else
- return (2);
- }
- else { /* 1, 11 */
- if (cmp(bl, br) != 0)
- return (1);
- else
- return (11);
- }
- }
- return 0;
- }
- /* read_next - read another line from input file */
- static int read_next(void)
- {
- int n;
- top = bottom++; /* switch top and bottom, */
- bottom = 1 & bottom; /* which are always 0 or 1 */
- n = read_row(buffer[bottom]);
- return (n);
- }
- /* alloc_bufs - allocate buffers we will need for storing raster map */
- /* data, pointers to extracted lines, area number information */
- int alloc_areas_bufs(int size)
- {
- int i;
- buffer[0] = (void *)G_malloc(size * data_size);
- buffer[1] = (void *)G_malloc(size * data_size);
- v_list = (struct COOR **)G_malloc(size * sizeof(*v_list));
- n_areas = n_equiv = 500; /* guess at number of areas, equivs */
- a_list =
- (struct area_table *)G_malloc(n_areas * sizeof(struct area_table));
- for (i = 0; i < n_areas; i++) {
- (a_list + i)->width = (a_list + i)->row = (a_list + i)->col = 0;
- (a_list + i)->free = 1;
- }
- a_list_new = a_list_old = a_list;
- e_list =
- (struct equiv_table *)G_malloc(n_equiv * sizeof(struct equiv_table));
- for (i = 0; i < n_equiv; i++) {
- (e_list + i)->mapped = (e_list + i)->count = 0;
- (e_list + i)->ptr = NULL;
- }
- return 0;
- }
- /* equiv_areas - force two areas to be equivalent and generate */
- /* mapping information */
- static int equiv_areas(int a1, int a2)
- {
- int small, large, small_obj, large_obj;
- if (a1 == -1 || a2 == -2)
- return 0;
- if (a1 == a2)
- return (0);
- if (a1 < a2) {
- small = a1;
- large = a2;
- }
- else {
- small = a2;
- large = a1;
- }
- while (large >= n_equiv) /* make sure our equivalence tables */
- more_equivs(); /* are large enough */
- if ((e_list + large)->mapped) {
- if ((e_list + small)->mapped) { /* small mapped, large mapped */
- large_obj = (e_list + large)->where;
- small_obj = (e_list + small)->where;
- if (large_obj == small_obj) /* both mapped to same place */
- return (0);
- if (small_obj < large_obj) /* map where large goes to where */
- map_area(large_obj, small_obj); /* small goes */
- else /* map where small goes to where */
- map_area(small_obj, large_obj); /* large goes */
- }
- else { /* small not mapped, large mapped */
- large_obj = (e_list + large)->where;
- if (small == large_obj) /* large already mapped to small */
- return (0);
- if (small < large_obj) /* map where large goes to small */
- map_area(large_obj, small);
- else /* map small to where large goes */
- map_area(small, large_obj);
- }
- }
- else {
- if ((e_list + small)->mapped) /* small mapped, large not mapped */
- map_area(large, (e_list + small)->where);
- else /* small not mapped, large not mapped */
- map_area(large, small);
- }
- return (0);
- }
- /* map_area - establish a mapping from one area to another */
- /* the area number mapping looks like the following: */
- /* area numbers index into e_list to get equiv_table structures */
- /* for each of these structures, */
- /* .mapped indicates whether area number is mapped */
- /* if area number is mapped */
- /* .where tells to what other area number */
- /* if area number is not mapped */
- /* .count tells how many areas are mapped to this one */
- /* if count != 0 */
- /* .ptr gives a pointer to the list of area numbers */
- static int map_area(int x, int y /* map x to y */
- )
- {
- int n, i, *p;
- (e_list + x)->mapped = 1;
- (e_list + x)->where = y;
- if ((a_list + x)->width > (a_list + y)->width) {
- (a_list + y)->width = (a_list + x)->width;
- (a_list + y)->row = (a_list + x)->row;
- (a_list + y)->col = (a_list + x)->col;
- }
- if (add_to_list(x, y)) { /* if x is not already in y's list */
- n = (e_list + x)->count;
- p = (e_list + x)->ptr;
- for (i = 0; i < n; i++) { /* map everything that is currently *//* mapped onto x onto y; because */
- (e_list + *p)->where = y; /* of this reshuffle, only one */
- add_to_list(*p++, y); /* level of mapping is ever needed */
- }
- }
- return 0;
- }
- /* add_to_list - add another area number to an equivalence list */
- static int add_to_list(int x, int y)
- {
- int n, i;
- struct equiv_table *e_list_y;
- e_list_y = e_list + y;
- n = e_list_y->count;
- if (n == 0) { /* first time through--start list */
- e_list_y->length = 20; /* initial guess at storage needed */
- e_list_y->ptr = (int *)G_malloc(e_list_y->length * sizeof(int));
- *(e_list_y->ptr) = x;
- (e_list_y->count)++;
- }
- else { /* list already started */
- for (i = 0; i < n; i++) { /* check whether x is already *//* in list */
- if (*(e_list_y->ptr + i) == x)
- return (0); /* if so, we don't need to add it */
- }
- if (n + 1 >= e_list_y->length) { /* add more space for storage *//* if necessary */
- e_list_y->length += 10;
- e_list_y->ptr =
- (int *)G_realloc(e_list_y->ptr,
- e_list_y->length * sizeof(int));
- }
- *(e_list_y->ptr + n) = x; /* add x to list */
- (e_list_y->count)++;
- }
- return (1); /* indicate addition made */
- }
- /* assign_area - make current area number correspond to the passed */
- /* category number and allocate more space to store areas if necessary */
- static int assign_area(double cat, int kase)
- {
- a_list_new->free = 0;
- a_list_new->cat = cat;
- area_num++;
- if (area_num >= n_areas)
- more_areas();
- a_list_old = a_list + area_num - 1;
- a_list_new = a_list + area_num;
- return 0;
- }
- /* more_areas - allocate larger space to store area correspondences */
- static int more_areas(void)
- {
- int old_n, i;
- old_n = n_areas;
- n_areas += 250;
- a_list =
- (struct area_table *)G_realloc(a_list,
- n_areas * sizeof(struct area_table));
- for (i = old_n; i < n_areas; i++) {
- (a_list + i)->width = -1;
- (a_list + i)->free = 1;
- }
- return 0;
- }
- /* more_equivs - allocate more space to construct equivalence information */
- int more_equivs(void)
- {
- int old_n, i;
- old_n = n_equiv;
- n_equiv += 250;
- e_list =
- (struct equiv_table *)G_realloc(e_list,
- n_equiv * sizeof(struct equiv_table));
- for (i = old_n; i < n_equiv; i++) {
- (e_list + i)->mapped = (e_list + i)->count = 0;
- (e_list + i)->ptr = NULL;
- }
- return 0;
- }
- /* update_width - update position of longest horizontal strip in an area */
- static int update_width(struct area_table *ptr, int kase)
- {
- int w, j, a;
- struct equiv_table *ep;
- a = (ptr - a_list);
- for (j = col + 1, w = 0; j < scan_length &&
- get_raster_value(buffer[bottom], j) == br; j++, w++) ;
- if (a == 0)
- G_debug(1, "Area 0, %d \t%d \t%d \t%d \t%d", kase, row, col,
- ptr->width, w);
- if (a < n_equiv) {
- ep = e_list + a;
- if (ep->mapped)
- ptr = a_list + ep->where;
- }
- if (w > ptr->width) {
- ptr->width = w;
- ptr->row = row;
- ptr->col = col;
- }
- return 0;
- }
|