====================================================================== GDF Routines ====================================================================== All gdf routines were written by Jim Meyer. Center for Morphometric Analysis Neuroscience Center Massachusetts General Hospital-East Building 149, 13th Street Charlestown MA 02129-2017 USA Documentation History: AJW Created Feb 7 1995 AJW Added table stuff Jan 23 1996 ********************************************************************* * * * (c) Copyright 1994,1995 The General Hospital Corporation * * All Rights Reserved * * * ********************************************************************* GENERAL GDF stands for Generic Data Format. Use it by loading and writing gdf files and then manipulating the data using the routines described below. GDF files have a main header that defines the defaults for the rest of the file. The rest of the file is made up of "blocks". Each block has a header and data. The bulk of data should be stored in the data portion of the blocks. The header must contain information describing the size and type of the bulk data, but can contain other associated descriptors (e.g a label) for that block. The programmer will usually design the data structure such that information pertinent to the entire series of data blocks is assigned to the main header and is absent in the block headers. Information retrieval routines query the main header after determining field is absent in the block header, so a specified block header value overrides the main header value. Headers are always ascii, both in memory and on file. The data blocks are always non-ascii in memory, but can be represented either as ascii or non-ascii on file. Here is an example (the gdf file is on the left and comments are on the right): GDF FILE VERSION3 | Main header: version ID START MAIN HEADER | Main header: TYPE short | Main header: field 0 COL_NUM 2 | Main header: field 1 ONUM 5 | Main header: ...etc... END MAIN HEADER | Main header: START GDF HEADER | BLock 0 header: ROW_NUM 248 | Block 0 header: field 0 SEED 309 301 | Block 0 header: field 1 LABEL Tumor Boundary | Block 0 header: ...etc... END GDF HEADER | Block 0 header: START POINTS | Block 0 data: | Block 0 data: bulk data here END POINTS | Block 0 data: START GDF HEADER | BLock 1 header: ROW_NUM 248 | Block 1 header: field 0 SEED 309 301 | Block 1 header: field 1 LABEL Tumor Boundary | Block 1 header: ...etc... END GDF HEADER | Block 1 header: START POINTS | Block 1 data: | Block 0 data: bulk data here END POINTS | Block 1 data: START GDF HEADER | ...etc... Header fields are stored as text and consist of: All gdf files will have the following fields: TYPE COL_NUM ROW_NUM Bulk data are stored in a COL_NUM by ROW_NUM array and have a that can be any C data type: char short double float long unsigned char unsigned short table /* gdf specific type for using mulitple C data types */ NOTE: All numbers in gdf files are assumed to be big endian since gdf was originally implemented on a Sun. This means the most significant byte of multiple-byte words are stored first (lower addresses). ---------------------------------------------------------------------- Access to GDF files ---------------------------------------------------------------------- GDF files are CREATED and allocated with: struct gdf_file *fi; fi_calloc(&fi); GDF files are READ into memory with char filnam[MAXPATHLEN]; struct gdf_file *fi; fi_calloc(&fi); strcpy(filnam,"mygdf.file"); if(read_gdf_file(filnam,fi)==-1) { fprintf(stderr,"couldn't open %s\n",filnam); } /* if */ NOTE: read_gdf_file() will free any previous information in fi before loading in the new information. GDF files are WRITTEN to disk with struct gdf_file *fi; wr_gdf_file("mygdf.file",fi); The number of data blocks in a gdf file is struct gdf_file *fi; fi->num A NEW data block can be ADDED by struct gdf_file *fi; add_block(fi,NULL,"",cols,rows) Existing data will be copied into a new data block by struct gdf_file *fi; *points; add_block(fi,points,"",cols,rows) ---------------------------------------------------------------------- Access to Header fields ---------------------------------------------------------------------- add_* add fields struct gdf_file *fi; int block_num; /* block number (use MAIN for the main header) */ char *field; /* text name of field */ char *value; double doub,doub1,doub2,doub3,doub4; int integ,integ1,integ2,integ3,integ4; add_string(fi,block_num,field,value) add_double(fi,block_num,field,doub) add_2double(fi,block_num,field,doub1,doub2) add_3double(fi,block_num,field,doub1,doub2,doub3) add_4double(fi,block_num,field,doub1,doub2,doub3,doub4) add_int(fi,block_num,field,integ) add_2int(fi,block_num,field,integ1,integ2) add_3int(fi,block_num,field,integ1,integ2,integ3) add_4int(fi,block_num,field,integ1,integ2,integ3,integ4) ---------------------------------------------------------------------- change_* change a field or adds a new one to the end change_double(fi,block_num,field,doub) change_2double(fi,block_num,field,doub1,doub2) change_3double(fi,block_num,field,doub1,doub2,doub3) change_4double(fi,block_num,field,doub1,doub2,doub3,doub4) change_int(fi,block_num,field,integ) change_2int(fi,block_num,field,integ1,integ2) change_3int(fi,block_num,field,integ1,integ2,integ3) change_4int(fi,block_num,field,integ1,integ2,integ3,integ4) ---------------------------------------------------------------------- find_* return values from the specified block_number or from the MAIN header if this field is not present in the given block. int block_num,cls; char *valuep; double slth; for one value: strcpy(valuep,find_string(fi,block_num,"")); cls = find_int(fi,block_num,COL_NUM); slth = find_double(fi,block_num,SL_THICK); for more than one value: int block_num; char *field; int sizex,sizey; double doub,doub1,doub2,doub3,doub4; int integ,integ1,integ2,integ3,integ4; if(find_2int(fi,block_num,SIZE,&sizex,&sizey)!=2) printf(stderr,"ERROR: find_2int(%d,SIZE) returned %d\n", block_num,rval"); if(find_3int(fi,block_num,field,&int1,&int2,&int3)!=3) printf(stderr,"ERROR: find_3int(%d,%s) returned %d\n", block_num,field,rval"); if(find_4int(fi,block_num,field,&int1,&int2,&int3,&int4)!=4) printf(stderr,"ERROR: find_4int(%d,%s) returned %d\n", block_num,field,rval"); if(find_2double(fi,block_num,field,&doub1,&doub2)!=2) printf(stderr,"ERROR: find_2double(%d,%s) returned %d\n", block_num,field,rval"); if(find_3double(fi,block_num,field,&doub1,&doub2,&doub3)!=3) printf(stderr,"ERROR: find_3double(%d,%s) returned %d\n", block_num,field,rval"); if(find_4double(fi,block_num,field,&doub1,&doub2,&doub3,&doub4)!=4) printf(stderr,"ERROR: find_3double(%d,%s) returned %d\n", block_num,field,rval"); ---------------------------------------------------------------------- Access to bulk data ---------------------------------------------------------------------- A pointer to the data for block number block_num can be had with struct gdf_file *fi; int block_num; *p; p = (fi->pts+block_num)->; or p = ( *)find_data(fi,block_num); where the data pionter depends on the of the data: ----------------- ---- char *cp; short *sp; double *dp; float *fp; long *lp; unsigned char *ucp; unsigned short *usp; struct pt *ptp; union point_types *unp; ---------------------------------------------------------------------- Access to tables ---------------------------------------------------------------------- A table is created with make_table(va_alist): struct gdf_file *fi; int rows,cols make_table(fi,rows,cols,type1,type2,type3,...); Where if typeN starts with a number it is a string with that number of charactes otherwise, it is one of the s as a string ("int", "double", etc). e.g. struct gdf_file *fi; make_table(fi,1,4,"35s","double","double","double"); Rows are added to the table using: struct gdf_file *fi; int onum; add_row(fi,onum); and then the information is added to that row using table_pointer(): e.g. struct gdf_file *fi; int onum,i; char *field; double dvar; i = find_int(fi,onum,ROW_NUM) - 1; strcpy((char *)table_pointer(fi,onum,0,i),field); /* for a string */ *((double *)table_pointer(fi,onum,1,0)+i) = dvar; /* for a double */ The routine add_info_point() in info_point.c gives an example of creating and adding rows to a table. Adding a column is done by: struct gdf_file *fi; int onum; char *type,*label,*format; add_column(fi,onum,type,label,format) e.g. add_column(fi_prcunits,0,"short","rant val",NULL); find_column_number(line,name) find_column_name(line,col_num) rm_table_info(temp,column_to_rm) ---------------------------------------------------------------------- Miscellaneous gdf commands and capabilities ---------------------------------------------------------------------- Editing GDF files as text You can create gdf files using a text editor. Here's how... (help!) ---------------------------------------------------------------------- GDF Routines ---------------------------------------------------------------------- add_block.c ---------------------------------------------------------------------- add_block(fi,points,type,cols,rows) add_column.c ---------------------------------------------------------------------- add_column(fi,onum,type,label,format) add_field.c ---------------------------------------------------------------------- add_field(va_alist) add_string(file_info,num,field,value) add_point.c ---------------------------------------------------------------------- add_point(va_alist) add_row.c ---------------------------------------------------------------------- add_row(fi,onum) change_field.c ---------------------------------------------------------------------- change_field(va_alist) change_string(file_info,num,field,value) check_field.c ---------------------------------------------------------------------- check_field(va_alist) cma_data.c ---------------------------------------------------------------------- read_otl(fi,pid,scn,pre,slice) write_otl(fi,pid,scn,pre,slice) write_nvol(fi,pid,scn,pre) read_nvol(fi,pid,scn,pre) read_info_file(fi,pid,scn) write_info_file(fi,pid,scn) cma_util.c ---------------------------------------------------------------------- get_date(file_name) norm_status(file_name) info_file_status(file_name) interpolate_points(pts,x1,y1,x2,y2) double distance(x1,y1,x2,y2) double distance_3d(xp1,yp1,zp1,xp2,yp2,zp2,xdm,ydm,zdm) double angle(x1,y1,x2,y2) void scale_points(pts_in,pts_out,num,scale) void scale_points2(pts_in,pts_out,num,scale_x,scale_y,orig_x,orig_y) void shift_points(pts_in,pts_out,num,xoff,yoff) int get_com(pts,num,cx,cy) match_point(pts,num,x,y) get_extents(pts,num,xmin,xmax,ymin,ymax) strip_rl(label_in,label_out) swap_rl(label_in,label_out) copy_file.c ---------------------------------------------------------------------- copy_file(fi1,fi2) cp_block.c ---------------------------------------------------------------------- cp_block(fi_to,fi_from,index) fac.c ---------------------------------------------------------------------- find_int(fi,onum,field) find_2int(fi,onum,field,int1,int2) find_3int(fi,onum,field,int1,int2,int3) find_4int(fi,onum,field,int1,int2,int3,int4) find_double(fi,onum,field) find_2double(fi,onum,field,doub1,doub2) find_3double(fi,onum,field,doub1,doub2,doub3) find_4double(fi,onum,field,doub1,doub2,doub3,doub4) add_double(fi,onum,field,doub) add_2double(fi,onum,field,doub1,doub2) add_3double(fi,onum,field,doub1,doub2,doub3) add_4double(fi,onum,field,doub1,doub2,doub3,doub4) add_int(fi,onum,field,integ) add_2int(fi,onum,field,integ1,integ2) add_3int(fi,onum,field,integ1,integ2,integ3) add_4int(fi,onum,field,integ1,integ2,integ3,integ4) change_double(fi,onum,field,doub) change_2double(fi,onum,field,doub1,doub2) change_3double(fi,onum,field,doub1,doub2,doub3) change_4double(fi,onum,field,doub1,doub2,doub3,doub4) change_int(fi,onum,field,integ) change_2int(fi,onum,field,integ1,integ2) change_3int(fi,onum,field,integ1,integ2,integ3) change_4int(fi,onum,field,integ1,integ2,integ3,integ4) de_zerodoub(doub) de_zero2doub(doub1,doub2) de_zero3doub(doub1,doub2,doub3) de_zero4doub(doub1,doub2,doub3,doub4) find_string(fi,onum,field) find_data(fi,onum) find_otl(fi,onum,pts,num) find_field.c ---------------------------------------------------------------------- find_field(file_info,num,field) free_file.c ---------------------------------------------------------------------- free_file(fi) gdf_random.c ---------------------------------------------------------------------- get_seed_point(fi,onum) - given an outline, return a valid seed for it. reverse_order(fi) gdf_extents(fi,onum,xmin,xmax,ymin,ymax,update_flg) gdf_com(fi,onum,xcm,ycm) gdf_area(fi,onum,update_flag) eliminate_red_points(fi,onum) gdflib.c ---------------------------------------------------------------------- void put_point_values(fi,onum,grid,inten_val,offset) void draw_lines(fi,onum,grid,fval) void insert_outline(pts1,num1,pts2,num2,pts3,num3) int make_map(fi,onum,grid,fval,code,user_func) int ovl_to_otl(fi_otl,fi_ovl,onum,threshold) int otl_to_ovl(fi_ovl,fi_otl,onum) int map_to_otl(map,sizex,sizey,fi_otl,extraction_order,extraction_num,innards_flg) int map_to_ovl(fi_map,map_index,fi_ovl) int gdf_edgext(grid,seed_x,seed_y,fi_otl,border_or_not,innards_flg) unsigned char * get_point_values(fi,onum,grid) int default_fill(),default_extract(),default_extract_inv(); int UCfill_num,fill_only_me,fill_only_me_func(); draw_lines(fi,onum,grid,fval) get_point_values(fi,onum,grid) put_point_values(fi,onum,grid,inten_val,offset) make_map(fi,onum,grid,fval,code,user_func) ovl_to_otl(fi_otl,fi_ovl,onum,threshold) otl_to_ovl(fi_ovl,fi_otl,onum) gdf_edgext(grid,seed_x,seed_y,fi_otl,border_or_not,innards_flg) closest_point(pts1,num1,pts2,num2,num3,num4) int extract_all_but_me,extract_all_but_me_func(); extract_all_but_me_func(val,x,y) which_comes_first(extraction_order,extraction_num,val1,val2) map_to_otl() - map_to_ovl(fi_map,map_index,fi_ovl) fill_only_me_func(val,x,y) smooth_map(map,sizex,sizey,threshold) get_aline.c ---------------------------------------------------------------------- get_aline(cp) grab_field.c ---------------------------------------------------------------------- grab_field(file_info,num,field) happy_order.c ---------------------------------------------------------------------- char *get_cortical_label(); get_number_of_parcunits() get_cortical_id(label) get_cortical_label(val) info_gdf.c ---------------------------------------------------------------------- find_xyzdim(fi,onum,xdim,ydim,zdim) find_ipres(fi,onum,ipx,ipy,slth) read_image_data(fi_in,fi_data) info_point.c ---------------------------------------------------------------------- find_info_point(fi,onum,field,cord) add_info_point(fi,onum,field,cord) change_info_point(fi,onum,field,cord) make_otl_data.c ---------------------------------------------------------------------- make_otl_data(file_info,header,onum) make_table.c ---------------------------------------------------------------------- make_table(va_alist) ascii_default_width(data_type) find_column_number(line,name) find_column_name(line,col_num) rm_table_info(temp,column_to_rm) mcalloc.c ---------------------------------------------------------------------- fi_calloc(fi) malloc_or_die(size) free_if_need(pointer) mcalloc_die(pointer) merge_file.c - this mergest gdf file fi2 into gdf file fi1. The resulting main header will be the amin header from fi1 plus any fields from fi2 which did not exist in fi1. ---------------------------------------------------------------------- merge_file(fi1,fi2) mv_block.c ---------------------------------------------------------------------- mv_block(fi_to,fi_from,index) next_field.c ---------------------------------------------------------------------- /* next_field(fi,num,style,field, ... , ... , "") */ int next_field(va_alist) query_field.c ---------------------------------------------------------------------- query_field(field) query_size.c ---------------------------------------------------------------------- query_size(type) read_gdf_file.c ---------------------------------------------------------------------- int read_gdf_file(filnam,file_info) read_pts.c ---------------------------------------------------------------------- read_pts(file_info,points,onum) rm_block.c ---------------------------------------------------------------------- rm_block(fi,onum) rm_column.c ---------------------------------------------------------------------- rm_column(fi,onum,column_to_rm) rm_field.c ---------------------------------------------------------------------- rm_field(file_info,num,field) strip_file.c ---------------------------------------------------------------------- strip_file(file_in,file_out,line_between_blocks) table_pointer.c ---------------------------------------------------------------------- table_pointer(fi,onum,col,row) wr_file_head.c ---------------------------------------------------------------------- wr_file_head(va_alist) wr_gdf_excel.c ---------------------------------------------------------------------- wr_gdf_excel(filnam,file_info,sep_char) write_excel_points(fpo,pts,type,dim,num,sep_char) wr_gdf_file.c ---------------------------------------------------------------------- wr_gdf_file(filnam,file_info) wr_gdf_head.c ---------------------------------------------------------------------- wr_gdf_head(va_alist) write_points.c ---------------------------------------------------------------------- UClib.c ---------------------------------------------------------------------- write_points(fpo,pts,type,dim,num) UCRectangle(grid,sizex,sizey,stx,sty,widthx,widthy,fval) UCCopy_Section(gridto,ssx,ssy,gridfrom,bsx,bsy,startx,starty,widthx,widthy) UCCopy(gridto,gridfrom,sizex,sizey,stx,sty,widthx,widthy) UCDrawLine(grid,sizex,sizey,fval,x1,y1,x2,y2) int UCFill(grid,sizex,sizey,seed_x,seed_y,fval,fill_or_not) int default_fill(val,x,y) int default_extract(val,x,y) int default_extract_inv(val,x,y) int UCEdgext(grid,sizex,sizey,seed_x,seed_y,pts,num,border_or_not) static point(x,y,pts,num,first_x,first_y,attempts)