void* dequeue(t_queue* queue) { void* datum=0; if (!ll_empty(queue)) { t_llist_node* node=ll_last(queue); datum=node->val; ll_delete_node(node); } return datum; }
/************************************************************************** * *N fc_row_numbers * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Given the starting row of a feature class relationship, return the * list of row numbers of the table at the end of the feature class * relate chain. * If your relate goes from the feature to the primitive, this will * return the primitive ids for the given feature row. * If your relate goes from the primitive to the feature, this will * return the feature ids of the given primitive row. * * Currently only supports relates on 'I' or 'K' fields. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ linked_list_type fc_row_numbers( row_type row, fcrel_type fcrel, long int tile, ThematicIndex *idx ) { row_type relrow; long int count; long int n, rownum, keyval; id_triplet_type triplet_keyval; int KEY1_, KEY_; position_type p, prow, pkey; vpf_relate_struct rcell; linked_list_type rowlist, keylist, templist; p = ll_first(fcrel.relate_list); ll_element(p,&rcell); KEY1_ = table_pos(rcell.key1,fcrel.table[0]); get_table_element(0,row,fcrel.table[0],&rownum,&count); if (KEY1_ == 0) { /* "ID" */ keyval = rownum; } else { switch (fcrel.table[0].header[KEY1_].type) { case 'I': get_table_element(KEY1_,row,fcrel.table[0],&keyval,&count); break; case 'K': get_table_element(KEY1_,row,fcrel.table[0],&triplet_keyval, &count); keyval = triplet_keyval.exid; if (tile != triplet_keyval.tile) { keyval = -2; } break; default: keyval = 0; break; } } keylist = ll_init(); ll_insert(&keyval,sizeof(keyval),keylist); n = 0; p = ll_first(fcrel.relate_list); for (n=1;n<(fcrel.nchain-1);n++) { /* Relate through Join table(s) */ rowlist = ll_init(); pkey = ll_first(keylist); while (!ll_end(pkey)) { ll_element(pkey,&keyval); templist = related_rows(&keyval,fcrel.table[n],rcell.key2,0,NULL); prow = ll_first(templist); while (!ll_end(prow)) { ll_element(prow,&rownum); if (!ll_locate(&rownum,rowlist)) ll_insert(&rownum,sizeof(rownum),ll_last(rowlist)); prow = ll_next(prow); } ll_reset(templist); pkey = ll_next(pkey); } ll_reset(keylist); p = ll_next(p); ll_element(p,&rcell); KEY_ = table_pos(rcell.key1,fcrel.table[n]); keylist = ll_init(); prow = ll_first(rowlist); while (!ll_end(prow)) { ll_element(prow,&rownum); relrow = get_row(rownum,fcrel.table[n]); if (KEY_ == 0) { /* "ID" */ keyval = rownum; } else { switch (fcrel.table[n].header[KEY_].type) { case 'I': get_table_element(KEY_,relrow,fcrel.table[n],&keyval,&count); break; case 'K': get_table_element(KEY_,relrow,fcrel.table[n],&triplet_keyval, &count); keyval = triplet_keyval.exid; if (tile != triplet_keyval.tile) { keyval = -2; } break; default: keyval = 0; break; } } if (keyval > 0) ll_insert(&keyval,sizeof(keyval),ll_last(keylist)); prow = ll_next(prow); free_row(relrow,fcrel.table[n]); } ll_reset(rowlist); } rowlist = ll_init(); p = ll_first(keylist); while (!ll_end(p)) { ll_element(p,&keyval); templist = related_rows(&keyval,fcrel.table[n],rcell.key2,0,idx); prow = ll_first(templist); while (!ll_end(prow)) { ll_element(prow,&rownum); if (!ll_locate(&rownum,rowlist)) ll_insert(&rownum,sizeof(rownum),ll_last(rowlist)); prow = ll_next(prow); } ll_reset(templist); p = ll_next(p); } ll_reset(keylist); return rowlist; }
/************************************************************************** * *N related_rows * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Return the list of related rows of table2 based upon the value of * table 1's key. * Supported data types - I and T<n>. * Binary search supported only for data type I. (column must be sorted) * Thematic index used, if present on key column. * NOTE: A sequential search operation will search the entire * table ...zzz... *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ linked_list_type related_rows( void *keyval1, vpf_table_type table2, char *key2, int sort_flag, ThematicIndex *idx ) { linked_list_type rowlist; set_type rowset; long int rowid, i, ival, kval, n, start,end; row_type row = 0; int KEY2_; char cval, *tval; rowlist = ll_init(); if (ossim_strcasecmp(key2,"ID")==0) { memcpy( &rowid, keyval1, sizeof(rowid) ); ll_insert(&rowid,sizeof(rowid),rowlist); return rowlist; } KEY2_ = table_pos(key2,table2); if ((table2.header[KEY2_].type != 'I')&& (table2.header[KEY2_].type != 'T')) return rowlist; if ((table2.header[KEY2_].type == 'I')&& (table2.header[KEY2_].count != 1)) return rowlist; if ((table2.header[KEY2_].type == 'T')&&(sort_flag)) sort_flag = 0; if (idx) { if (idx->fp) { rowset = search_thematic_index(idx,(char *)keyval1); start = set_min(rowset); end = set_max(rowset); for (i=start;i<=end;i++) if (set_member(i,rowset)) { ll_insert(&i,sizeof(i),ll_last(rowlist)); } set_nuke(&rowset); return rowlist; } } if (!sort_flag) { /* Sequential search */ for (i=1;i<=table2.nrows;i++) { row = get_row(i,table2); if (table2.header[KEY2_].type == 'I') { get_table_element(KEY2_,row,table2,&ival,&n); if (memcmp(&ival,keyval1,sizeof(ival))==0) ll_insert(&i,sizeof(i),ll_last(rowlist)); } else { if (table2.header[KEY2_].count==1) { get_table_element(KEY2_,row,table2,&cval,&n); if (memcmp(&cval,keyval1,sizeof(ival))==0) ll_insert(&i,sizeof(i),ll_last(rowlist)); } else { tval = (char*)get_table_element(KEY2_,row,table2,NULL,&n); if (strcmp(tval,(char *)keyval1)==0) ll_insert(&i,sizeof(i),ll_last(rowlist)); } } free_row(row,table2); } } else { /* Binary search */ memcpy(&kval,keyval1,sizeof(kval)); rowid = vpf_binary_search( kval, KEY2_, table2 ); if (rowid > 0) { ll_insert(&rowid,sizeof(rowid),ll_last(rowlist)); i = rowid-1L; do { get_row(i,table2); get_table_element(KEY2_,row,table2,&ival,&n); if (ival == kval) ll_insert(&i,sizeof(i),ll_last(rowlist)); i--; } while ((ival==kval)&&(i>0)); i = rowid+1L; do { get_row(i,table2); get_table_element(KEY2_,row,table2,&ival,&n); if (ival == kval) ll_insert(&i,sizeof(i),ll_last(rowlist)); i++; } while ((ival==kval)&&(i<=table2.nrows)); } } return rowlist; }
/************************************************************************** * *N fcs_relate_list * *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * Read the feature class schema table and create the list of * tables to chain through. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * fcname <input> == (char *) feature class name. * start_table <input> == (char *) table to start from. * end_table <input> == (char *) table to end with. * fcs <input> == (vpf_table_type) feature class schema table. * fcs_relate_list <output> == (linked_list_type) list of tables to * chain through. *E *::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels DOS Turbo C *E *************************************************************************/ linked_list_type fcs_relate_list( char *fcname, char *start_table, char *end_table, vpf_table_type fcs ) { linked_list_type rlist; vpf_relate_struct rstruct; set_type fcset, set1, set2; char tablename[255], *buf, expr[255]; row_type row; long int rownum,n; int TABLE1_, KEY1_, TABLE2_, KEY2_; rlist = ll_init(); sprintf(expr,"FEATURE_CLASS = %s",fcname); fcset = query_table(expr,fcs); if (set_empty(fcset)) { set_nuke(&fcset); return rlist; } TABLE1_ = table_pos("TABLE1",fcs); KEY1_ = table_pos("FOREIGN_KEY",fcs); if (KEY1_ < 0) KEY1_ = table_pos("TABLE1_KEY",fcs); TABLE2_ = table_pos("TABLE2",fcs); KEY2_ = table_pos("PRIMARY_KEY",fcs); if (KEY2_ < 0) KEY2_ = table_pos("TABLE2_KEY",fcs); strcpy( tablename, start_table ); while (1) { sprintf(expr,"TABLE1 = %s",tablename); set1 = query_table(expr,fcs); set2 = set_intersection(set1,fcset); set_nuke(&set1); if (set_empty(set2)) { set_nuke(&fcset); set_nuke(&set2); return rlist; } rownum = set_min(set2); set_nuke(&set2); row = get_row(rownum,fcs); buf = (char *)get_table_element(TABLE1_,row,fcs,NULL,&n); strcpy(rstruct.table1,buf); rightjust(rstruct.table1); free(buf); buf = (char *)get_table_element(KEY1_,row,fcs,NULL,&n); strcpy(rstruct.key1,buf); rightjust(rstruct.key1); free(buf); buf = (char *)get_table_element(TABLE2_,row,fcs,NULL,&n); strcpy(rstruct.table2,buf); rightjust(rstruct.table2); free(buf); buf = (char *)get_table_element(KEY2_,row,fcs,NULL,&n); strcpy(rstruct.key2,buf); rightjust(rstruct.key2); free(buf); rstruct.degree = R_ONE; /* Default */ free_row( row, fcs ); if (table_in_list(rstruct.table1, rlist)) break; ll_insert( &rstruct, sizeof(rstruct), ll_last(rlist) ); strcpy( tablename, rstruct.table2 ); if (ossim_strcasecmp(tablename,end_table)==0) break; } set_nuke(&fcset); return rlist; }
/************************************************************************* * *N get_selected_tile_primitives * *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * This function determines all of the selected primitive rows from * the selected features of a given tile. * * This function expects a feature class relationship structure that * has been successfully created with select_feature_class_relate() * from the feature table to the primitive. The primitive table in * the feature class relate structure must have been successfully * opened for the given tile. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * library <input>==(library_type *) VPF library structure. * fcnum <input>==(int) feature class number of the feature table. * fcrel <input>==(fcrel_type) feature class relate structure. * feature_rows <input>==(set_type) set of selected features. * mapenv <input>==(map_environment_type *) map environment. * tile <input>==(rspf_int32) tile number. * tiledir <input>==(char *) path to the tile directory. * status <output>==(int *) status of the function: * 1 if completed, 0 if user escape. * return <output>==(set_type) set of primitives for the features * in the corresponding tile. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels May 1991 DOS Turbo C *E *************************************************************************/ set_type get_selected_tile_primitives( library_type *library, int fcnum, fcrel_type fcrel, set_type feature_rows, map_environment_type *mapenv, rspf_int32 tile, char *tiledir, int *status ) { int cov, degree; int feature, prim; row_type row; char *spxname[] = {"","esi","fsi","tsi","nsi","csi"}; char *brname[] = {"","ebr","fbr","tbr","nbr","cbr"}; set_type primitive_rows, tile_features; set_type primitives; rspf_int32 prim_rownum; register rspf_int32 i,pclass, start,end; char path[255], covpath[255]; linked_list_type primlist; position_type p; vpf_relate_struct rcell; ThematicIndex idx; feature = 0; prim = fcrel.nchain-1; /* Assume that fcrel.table[prim] has been opened */ primitives.size = 0; primitives.buf = NULL; cov = library->fc[fcnum].coverage; strcpy( covpath, library->cover[cov].path ); p = ll_previous(ll_last(fcrel.relate_list),fcrel.relate_list); ll_element(p,&rcell); degree = rcell.degree; for (pclass=EDGE;pclass<=CONNECTED_NODE;pclass++) { if ((pclass != library->fc[fcnum].primclass) && (library->fc[fcnum].primclass != COMPLEX_FEATURE)) continue; primitives = set_init(fcrel.table[prim].nrows+1); /* Get the set of primitive rows within the map extent */ /* Look for the spatial index file to weed out primitives in the */ /* given tile but outside of the viewing area. If a projection */ /* other than plate-carree (rectangular) is on, or if the extent */ /* crosses the meridian, the quick check is no longer valid. */ primitive_rows.size = 0; if (mapenv->projection == PLATE_CARREE && mapenv->mapextent.x1 < mapenv->mapextent.x2) { sprintf(path,"%s%s%s",covpath,tiledir,spxname[pclass]); /* 20 (below) is a fairly arbitrary cutoff of the number of */ /* primitives that make a spatial index search worth while. */ if ((access(path,0)==0)&&(fcrel.table[prim].nrows > 20)) { primitive_rows = spatial_index_search(path, mapenv->mapextent.x1,mapenv->mapextent.y1, mapenv->mapextent.x2,mapenv->mapextent.y2); } else { /* Next best thing - bounding rectangle table */ sprintf(path,"%s%s%s",covpath,tiledir,brname[pclass]); if ((access(path,0)==0)&&(fcrel.table[prim].nrows > 20)) { primitive_rows = bounding_select(path,mapenv->mapextent, library->dec_degrees); } } } if (primitive_rows.size == 0) { /* Search through all the primitives */ primitive_rows=set_init(fcrel.table[prim].nrows+1); set_on(primitive_rows); } if (strcmp(tiledir,"") != 0) { tile_thematic_index_name(fcrel.table[feature], path); if ((strcmp(path,"")!=0) && (access(path,4)==0)) { /* Tile thematic index for feature table present, */ tile_features = read_thematic_index( path, (char *)&tile ); } else { tile_features = set_init(fcrel.table[feature].nrows+1); set_on(tile_features); } } else { tile_features = set_init(fcrel.table[feature].nrows+1); set_on(tile_features); } set_delete(0,tile_features); idx.fp = NULL; i = table_pos(rcell.key2,fcrel.table[prim]); if (i >= 0) { if (fcrel.table[prim].header[i].tdx) { sprintf(path,"%s%s",fcrel.table[prim].path, fcrel.table[prim].header[i].tdx); if (access(path,0)==0) idx = open_thematic_index(path); } if (fcrel.table[prim].header[i].keytype == 'U') degree = R_ONE; if (fcrel.table[prim].header[i].keytype == 'N') degree = R_MANY; if (fcrel.table[prim].header[i].keytype == 'P') degree = R_ONE; } start = set_min(tile_features); end = set_max(tile_features); /* It turns out to be MUCH faster off of a CD-ROM to */ /* read each row and discard unwanted ones than to */ /* forward seek past them. It's about the same off */ /* of a hard disk. */ fseek(fcrel.table[feature].fp,index_pos(start,fcrel.table[feature]), SEEK_SET); for (i=start;i<=end;i++) { row = read_next_row(fcrel.table[feature]); if (!set_member( i, feature_rows )) { free_row(row,fcrel.table[feature]); continue; } if (!set_member( i, tile_features )) { free_row(row,fcrel.table[feature]); continue; } if (degree == R_ONE) { prim_rownum = fc_row_number( row, fcrel, tile ); primlist = NULL; p = NULL; } else { primlist = fc_row_numbers( row, fcrel, tile, &idx ); } free_row( row, fcrel.table[feature] ); if (!primlist) { if ((prim_rownum<1)||(prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives); } } else { p = ll_first(primlist); while (!ll_end(p)) { ll_element(p,&prim_rownum); if ((prim_rownum<1)|| (prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives); } p = ll_next(p); } } if (primlist) ll_reset(primlist); if (kbhit()) { if (getch()==27) { *status = 0; break; } } } set_nuke(&primitive_rows); set_nuke(&tile_features); if (idx.fp) close_thematic_index(&idx); *status = 1; if (kbhit()) { if (getch()==27) { *status = 0; break; } } } return primitives; }
/************************************************************************* * *N get_selected_primitives * *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Purpose: *P * This function determines all of the selected primitive rows from * the selected features. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * Parameters: *A * view <input> == (view_type *) view structure. * themenum <input> == (int) theme number. * library <input> == (library_type *) VPF library structure. * mapenv <input> == (map_environment_type *) map environment. * status <output> == (int *) status of the function: * 1 if completed, 0 if user escape. * get_selected_primitives <output> == (set_type *) array of sets, each position * representing the set of primitives for the * corresponding tile in the tileref.aft table. *E *:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * History: *H * Barry Michaels May 1991 DOS Turbo C *E *************************************************************************/ set_type *get_selected_primitives( view_type *view, int themenum, library_type *library, map_environment_type *mapenv, int *status ) { int fcnum, finished, found, cov, tilecover, TILEPATH_, degree; int feature, prim; vpf_table_type tile_table; row_type row; char *ptable[] = {"","edg","fac","txt","end","cnd"}; char *spxname[] = {"","esi","fsi","tsi","nsi","csi"}; char *brname[] = {"","ebr","fbr","tbr","nbr","cbr"}; set_type feature_rows, primitive_rows, tile_features; set_type *primitives; rspf_int32 prim_rownum, count, tile; register rspf_int32 i,j, pclass, start,end; char path[255], covpath[255], tiledir[255], *buf, str[255]; fcrel_type fcrel; linked_list_type primlist; position_type p; vpf_relate_struct rcell; ThematicIndex idx; primitives = (set_type *)vpfmalloc((library->ntiles+1)*sizeof(set_type)); for (i=0;i<=library->ntiles;i++) { primitives[i].size = 0; primitives[i].buf = NULL; } fcnum = view->theme[themenum].fcnum; feature_rows = get_selected_features( view, themenum, *library ); /* Open the tile reference table, if present */ sprintf(path,"%stileref\\tileref.aft",library->path); if (access(path,0) != 0) { tilecover = FALSE; } else { tile_table = vpf_open_table(path,disk,"rb",NULL); TILEPATH_ = table_pos("TILE_NAME",tile_table); tilecover = TRUE; } for (pclass=EDGE;pclass<=CONNECTED_NODE;pclass++) { if ((pclass != library->fc[fcnum].primclass) && (library->fc[fcnum].primclass != COMPLEX_FEATURE)) continue; /* Set up the feature class table relate chain. */ /* The feature table is fcrel.table[0]. */ /* The primitive table is the last table in the chain: */ /* fcrel.table[ fcrel.nchain-1 ]. */ j = 0; for (i=0;i<strlen(library->fc[fcnum].table);i++) if (library->fc[fcnum].table[i] == '\\') j = i+1; strcpy( str, &(library->fc[fcnum].table[j])); fcrel = select_feature_class_relate(fcnum, library, str, ptable[pclass]); feature = 0; prim = fcrel.nchain-1; p = ll_previous(ll_last(fcrel.relate_list),fcrel.relate_list); ll_element(p,&rcell); degree = rcell.degree; /*** 'Tile' number 1 is the universe polygon for the tileref cover ***/ for (tile = 2; tile <= library->ntiles; tile++ ) { if (!set_member(tile,library->tile_set)) continue; if (tilecover) { row = get_row(tile,tile_table); buf = (char *)get_table_element(TILEPATH_,row,tile_table, NULL,&count); free_row(row,tile_table); strcpy(tiledir,buf); rightjust(tiledir); strcat(tiledir,"\\"); free(buf); } else { strcpy(tiledir,""); } cov = library->fc[fcnum].coverage; strcpy( covpath, library->cover[cov].path ); finished = 1; found = 0; /* Open primitive table in tile */ sprintf(path,"%s%s%s",covpath,tiledir,ptable[pclass]); if (access(path,0) != 0) continue; found = 1; fcrel.table[prim] = vpf_open_table(path,disk,"rb",NULL); if (primitives[tile].size > 0) { printf("Oops! size = %ld\n",primitives[tile].size); exit(1); } primitives[tile] = set_init(fcrel.table[prim].nrows+1); /* Get the set of primitive rows within the map extent */ /* Look for spatial index file */ primitive_rows.size = 0; if (mapenv->projection == PLATE_CARREE && mapenv->mapextent.x1 < mapenv->mapextent.x2) { sprintf(path,"%s%s%s",covpath,tiledir,spxname[pclass]); if ((access(path,0)==0)&&(fcrel.table[prim].nrows > 20)) { primitive_rows = spatial_index_search(path, mapenv->mapextent.x1,mapenv->mapextent.y1, mapenv->mapextent.x2,mapenv->mapextent.y2); } else { /* Next best thing - bounding rectangle table */ sprintf(path,"%s%s%s",covpath,tiledir,brname[pclass]); if (access(path,0)==0) { primitive_rows = bounding_select(path,mapenv->mapextent, library->dec_degrees); } } } /* projection check */ if (primitive_rows.size == 0) { /* Search through all the primitives */ primitive_rows=set_init(fcrel.table[prim].nrows+1); set_on(primitive_rows); } tile_thematic_index_name(fcrel.table[feature], path); if ( (strcmp(path,"") != 0) && (access(path,4)==0) ) { /* Tile thematic index for feature table present, */ tile_features = read_thematic_index( path, (char *)&tile ); } else { tile_features = set_init(fcrel.table[feature].nrows+1); set_on(tile_features); } idx.fp = NULL; i = table_pos(rcell.key2,fcrel.table[prim]); if (i >= 0) { if (fcrel.table[prim].header[i].tdx) { sprintf(path,"%s%s",fcrel.table[prim].path, fcrel.table[prim].header[i].tdx); if (access(path,0)==0) idx = open_thematic_index(path); } if (fcrel.table[prim].header[i].keytype == 'U') degree = R_ONE; if (fcrel.table[prim].header[i].keytype == 'N') degree = R_MANY; if (fcrel.table[prim].header[i].keytype == 'P') degree = R_ONE; } finished = 1; start = set_min(tile_features); end = set_max(tile_features); fseek(fcrel.table[feature].fp, index_pos(start,fcrel.table[feature]), SEEK_SET); for (i=start;i<=end;i++) { row = read_next_row(fcrel.table[feature]); if (!set_member( i, feature_rows )) { free_row(row,fcrel.table[feature]); continue; } if (!set_member( i, tile_features )) { free_row(row,fcrel.table[feature]); continue; } if (degree == R_ONE) { prim_rownum = fc_row_number( row, fcrel, tile ); primlist = NULL; p = NULL; } else { primlist = fc_row_numbers( row, fcrel, tile, &idx ); } free_row( row, fcrel.table[feature] ); if (!primlist) { if ((prim_rownum<1)|| (prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives[tile]); } } else { p = ll_first(primlist); while (!ll_end(p)) { ll_element(p,&prim_rownum); if ((prim_rownum<1)|| (prim_rownum>fcrel.table[prim].nrows)) continue; if (set_member( prim_rownum, primitive_rows )) { set_insert(prim_rownum,primitives[tile]); } p = ll_next(p); } } if (kbhit()) { if (getch()==27) { *status = 0; finished = 0; break; } } } if (idx.fp) close_thematic_index(&idx); vpf_close_table(&(fcrel.table[prim])); set_nuke(&primitive_rows); set_nuke(&tile_features); if (set_empty(primitives[tile])) { set_nuke(&primitives[tile]); primitives[tile].size = 0; primitives[tile].buf = NULL; } if (!finished) { *status = 0; break; } } if (!finished) { *status = 0; deselect_feature_class_relate( &fcrel ); break; } if (found) *status = 1; if (kbhit()) { if (getch()==27) { *status = 0; deselect_feature_class_relate( &fcrel ); break; } } deselect_feature_class_relate( &fcrel ); } set_nuke(&feature_rows); if (tilecover) { vpf_close_table(&tile_table); } return primitives; }