static char *RCSid="$Id: process_exch.c,v 1.3 2001/02/01 21:32:36 jwm Exp $"; /*********************************************************************** * process_exch.c * Description: Process all patient exchange file types into the * internal Tape Exchange data structures and then calls routines which * convert this internal format into the host RTP system format and * saves the converted files. * * Contains the following routines: * process_ct() Opens and processes AAPM formatted CT file and * dispatches data to user supplied RTP * conversion and storage routine 'save_ct()'. * * process_mrus() Opens and processes AAPM formatted MR or US file * and dispatches data to user supplied RTP * conversion and storage routine 'save_mrus()'. * * process_structures() Opens and processes AAPM formatted anatomic * structure file and dispatches to user supplied * RTP conversion and storage routine * 'save_structures()'. * * process_dose() Opens and processes AAPM formatted dose file * and dispatches to user supplied RTP conversion * and storage routine 'save_doses()'. * * process_comment() Opens and processes AAPM formatted comment * file and dispatches to user supplied RTP * conversion and storage routine * 'save_comment()'. * * add_comment_line() Places a text string (read from an AAPM * formatted comment file) into the comment * data structure linked list. * * process_beam_geometry() Opens and processes AAPM formatted beam * geometry file and dispatches to user supplied * RTP conversion and storage routine * 'save_beam()'. * * process_seed_geometry() Opens and processes AAPM formatted seed * geometry file and dispatches to user supplied * RTP conversion and storage routine * 'save_seed()'. * * process_digital_film() Opens and processes AAPM formatted digital * film file and dispatches to user supplied * RTP conversion and storage routine * 'save_film()'. * * process_dvh() Opens and process AAPM formatted dose-volume * histogram (DVH) file and dispatches to user * supplied RTP conversion and storage routine * 'save_dvh()'. * * allocate_mlc() Allocates the MLC data structure required by * process_beam_geometry for any beams containing * MLC. * * allocate_leafs() Allocates the MLC leafs data structure required * by process_beam_geometry for any beams * containing MLC. * *********************************************************************** * $Log: process_exch.c,v $ * Revision 1.3 2001/02/01 21:32:36 jwm * Correct code that would have "free"ed same buffer twice * * Revision 1.2 2000/01/20 20:04:42 jwm * Remove save_seed_dose from generic code * * Revision 1.1 2000/01/14 23:54:47 jwm * Remove comments originating in other development trees * * Revision 1.0 2000/01/14 23:53:26 jwm * Initial revision **********************************************************************/ /* Include Files */ #include #include #include #include #include #include #include #include #include "sitedata.h" #define NOT_MAIN #include "exchkeys.h" #include "patexchange.h" /* LOCAL PROTOTYPES */ static int add_comment_line /* STASH COMMENT LINE IN STRUCTURE LIST */ ( exch_file_t *file, /* TAPE FILE NODE TO BE SAVED */ char *string /* STRING TO SAVE */ ); static mlc_def_t *allocate_mlc ( beam_definition_t *beam_ptr, /* POINTER TO BEAM STRUCTURE */ exch_file_t *cur_file, /* EXCHANGE FILE DIRECTORY ENTRY */ int number_of_leafs /* NUMBER OF LEAFS IN THIS MLC */ ); static int allocate_leafs ( mlc_def_t *mlc_ptr, /* MLC POINTER */ int number_of_leafs /* NUMBER OF LEAFS IN THIS MLC */ ); static int check_z ( float const_z, /* CONTOUR Z COORDINATE */ int scan_num, /* SCAN NUMBER */ case_t *p_case, /* LINKED LIST OF PATIENT FILES */ float *scan_z /* Z COORDINATE OF SCAN NUMBER RETURNED */ ); /***************************************************************************** process_ct() **************************************************************************** Functional Description: Processes ct scan file from tape exchange format and calls routine to convert and write the file out. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int process_ct ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILENAME FOR CT INPUT FILE */ int num_blocks; /* PARAMETERS FOR CT FILE */ FILE *fp; size_t read_size; /* SIZE OF DATA READ */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_cts == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS, IS THE CORRECT SIZE AND OPEN IT */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &fp, filename, tape->block_size, &num_blocks, &file->data_size ) != SUCCESS ) { /* LET USER KNOW A PROBLEM OCCURRED */ sprintf( aapm_log_string, "Error opening exchange CT file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* MAKE SURE FILE SIZE IS CONSISTENT WITH IMAGE SIZE */ if ( file->data_size != (file->image.ctscan.dimension_1 * file->image.ctscan.dimension_2 * sizeof( short )) && tape->block_size == 0 ) { sprintf( aapm_log_string, "Incorrect CT scan file size. Is %d should be %d", file->data_size, file->image.ctscan.dimension_1 * file->image.ctscan.dimension_2 * sizeof( short )); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* ALLOCATE AND READ IN THE DATA */ if ( (file->image.ctscan.pixbuf = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for CT data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)file->image.ctscan.pixbuf, (size_t)1, (size_t)file->data_size, fp )) != file->data_size ) { sprintf( aapm_log_string, "Error reading CT file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", num_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)file->image.ctscan.pixbuf ); fclose( fp ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( fp ); /* SEND CT DATA TO RTP SYSTEM FILE HANDLING ROUTINE */ if ( save_ct( p_case, file ) != SUCCESS ) { sprintf( aapm_log_string, "Error converting CT file to rtp format" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)file->image.ctscan.pixbuf ); return( FAILURE ); } /* FREE THE CT DATA BLOCK */ free( (void *)file->image.ctscan.pixbuf ); return( SUCCESS ); } /*********************** End of process_ct() **************************/ /* */ /*********************************************************************** process_mrus() ********************************************************************** Functional Description: Processes MR or US scan file from tape exchange format and calls routine to convert and write the file out. Returns SUCCESS or FAILURE on an error. *********************************************************************/ int process_mrus ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILENAME FOR MR/US INPUT FILE */ int num_blocks; /* PARAMETERS FOR MR/US FILE */ FILE *fp; size_t read_size; /* SIZE OF DATA READ */ /* ONLY PROCESS IF FLAG IS SET */ if( (file->image_flag == eMRISCAN) && (p_case->site_data.process_flags.do_mris == 0) ) return( SUCCESS ); if( (file->image_flag == eUSSCAN) && (p_case->site_data.process_flags.do_us == 0) ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS, IS THE CORRECT SIZE AND OPEN IT */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &fp, filename, tape->block_size, &num_blocks, &file->data_size ) != SUCCESS ) { /* LET USER KNOW A PROBLEM OCCURRED */ sprintf( aapm_log_string, "Error opening exchange MR/US file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* MAKE SURE FILE SIZE IS CONSISTENT WITH IMAGE SIZE */ if ( file->data_size != (file->image.mrusscan.dimension_1 * file->image.mrusscan.dimension_2 * sizeof( short )) && tape->block_size == 0 ) { sprintf( aapm_log_string, "Incorrect MR/US scan file size. Is %d should be %d", file->data_size, file->image.mrusscan.dimension_1 * file->image.mrusscan.dimension_2 * sizeof( short )); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* ALLOCATE AND READ IN THE DATA */ if ( (file->image.mrusscan.pixbuf = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for MR/US data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)file->image.mrusscan.pixbuf, (size_t)1, (size_t)file->data_size, fp )) != file->data_size ) { sprintf(aapm_log_string, "Error reading MR/US file: %s", filename); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", num_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)file->image.mrusscan.pixbuf ); fclose( fp ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( fp ); /* SEND CT DATA TO RTP SYSTEM FILE HANDLING ROUTINE */ if ( save_mrus( p_case, file ) != SUCCESS ) { sprintf( aapm_log_string, "Error converting MR/US file to rtp format" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)file->image.mrusscan.pixbuf ); return( FAILURE ); } /* FREE THE MR/US DATA BLOCK */ free( (void *)file->image.mrusscan.pixbuf ); return( SUCCESS ); } /********************* End of process_mrus() **************************/ /* */ /***************************************************************************** process_structures() **************************************************************************** Functional Description: Processes anatomic structure file from tape exchange format and calls routine to convert the data to RTP system format and write the file out. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int process_structures ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILENAME FOR CT INPUT FILE */ int num_blocks; /* PARAMETERS FOR CT FILE */ FILE *fp; int retval; /* RETURN VALUE */ size_t read_size; /* SIZE OF DATA READ */ char *block_data; /* FORMATTED TAPE BLOCK DATA */ int offset; /* OFFSET IN DATA ARRAY */ state_type action_state; /* eNUM_LEVEL | eSCAN_NUM | eNUM_SEGMENTS | eNUM_POINTS | eSTRUCT_COORD */ char string[MAX_LINE_LENGTH]; /* STRING READ OUT OF BLOCK DATA */ int n_levels; /* NUMBER OF LEVELS OF STRUCTS */ int int_array[20]; /* INTEGER ARRAY TO BE FILLED */ float float_array[20]; /* FLOATING ARRAY TO BE FILLED */ int scan_number; /* SCAN # OF CURRENT LEVEL OF STRUCT */ int n_segments; /* # OF SEGMENTS THIS LEVEL */ int n_points; /* # OF POINTS THIS SEGMENT */ int cur_point; /* ARRAY INDEX FOR CONTOUR */ structurelist_t *contour; /* LOCAL POINTER TO CONTOUR ARRAY */ structurelist_t *temp; /* LOCAL POINTER TO CONTOUR ARRAY */ int cur_segment; /* CURRENT SEGMENT NUMBER */ int scan_count; /* NUMBER OF SCANS FOR THIS STRUCTURE */ float const_z; /* CONSTANT COORD FOR A SCAN NUMBER TO ENSURE NO CHANGES IN Z FOR A SINGLE SCAN */ float scan_z = 0; /* COORDINATE OF ASSOCIATED SCAN */ int scan_count_increment; /* CORRECT FOR ZERO BASED SCAN NUMBERS TO DIMINISH NUMBER OF ERROR MESSAGES */ int mismatch; /* COUNT OF MISMATCHED CONTOUR POINTS VERSUS SCAN COORDINATE TO MINIMIZE THE ERROR MESSAGES */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_structures == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS, IS THE CORRECT SIZE AND OPEN IT */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &fp, filename, tape->block_size, &num_blocks, &file->data_size ) != SUCCESS ) { /* LET USER KNOW A PROBLEM OCCURRED */ sprintf( aapm_log_string, "Error opening structure file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALLOCATE AND READ IN THE DATA */ if ( (block_data = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for structure data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)block_data, (size_t)1, (size_t)file->data_size, fp )) != file->data_size ) { sprintf( aapm_log_string, "Error reading structure file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", num_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); fclose( fp ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( fp ); /* INITIALIZE scan_count_increment TO INDICATE THAT THE FIRST SCAN NUMBER HAS NOT YET BEEN LOCATED */ scan_count_increment = -1; /* READ THE STRUCTURE DATA OUT OF THE DATA BLOCKS */ offset = 0; action_state = eNUM_LEVEL; while( offset < file->data_size ) { if ( extract_line( block_data, &offset, file->data_size, string, MAX_LINE_LENGTH ) == FAILURE ) { sprintf( aapm_log_string, "Error extracting data out of structure data buffer " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } /* SKIP BLANK LINES */ if ( strlen( string ) == 0 ) continue; switch( action_state ) { case eNUM_LEVEL: if ( (extract_ints( string, int_array, 20 )) != 1 ) { sprintf( aapm_log_string, "Error extracting number of levels from structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } n_levels = int_array[0]; action_state = eSCAN_NUM; scan_count = 0; break; case eSCAN_NUM: if ( (extract_ints( string, int_array, 20 )) != 1 ) { sprintf( aapm_log_string, "Error extracting scan number from structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } scan_number = int_array[0]; action_state = eNUM_SEGMENTS; scan_count++; /* SEE IF THE FIRST SCAN NUMBER IS '1', OTHERWISE SET THE INCREMENT */ if ( scan_count_increment < 0 ) { switch( scan_number ) { case 0: /* SCAN NUMBERS ARE 0 BASED, SHOULD BE 1 BASED */ scan_count_increment = 1; scan_number = scan_number + scan_count_increment; sprintf( aapm_log_string, "Scan #'s in structure files are zero based" ); aapm_status( eAAPM_ERROR, aapm_log_string ); break; case 1: /* SCAN NUMBER ARE CORRECTLY 1 BASED */ scan_count_increment = 0; break; default: /* A SIGNIFICANT ERROR HAS BEEN ENCOUNTERED. LET LIFE TAKE IT (UN)NATURAL COURSE */ scan_count_increment = 0; sprintf( aapm_log_string, "First scan # in contour file is %d", scan_number ); aapm_status( eAAPM_ERROR, aapm_log_string ); break; } /* END scan_number SWITCH */ } /* END OF INCREMENT INITIALIZATION CHECK */ else /* ADD THE APPROPRIATE INCREMENT */ scan_number += scan_count_increment; break; case eNUM_SEGMENTS: if ( (extract_ints( string, int_array, 20 )) != 1 ) { sprintf( aapm_log_string, "Error extracting number of segments from structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } n_segments = int_array[0]; if ( n_segments > 1 ) { sprintf( aapm_log_string, "Unusual number of contours (%d) in scan #%d for %s", n_segments, scan_number, file->image.structure.struct_name ); aapm_status( eAAPM_WARN, aapm_log_string ); } cur_segment = 1; if ( n_segments == 0 ) { if ( scan_count < n_levels ) action_state = eSCAN_NUM; else /* FORCE TERMINATION OF PROCESSING */ offset = file->data_size + 1; } else action_state = eNUM_POINTS; /* INITIALIZE THE MISMATCH COUNT */ mismatch = 0; break; case eNUM_POINTS: if ( (extract_ints( string, int_array, 20 )) != 1 ) { sprintf( aapm_log_string, "Extracting number of points from structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } /* ENSURE THAT THERE IS MORE THAN ZERO POINTS AT THIS LEVEL */ if ( int_array[0] < 1 ) { /* REPORT ERROR, BUT TRY TO KEEP PROCESSING */ sprintf( aapm_log_string, "Scan #%d has %d points for at least 1 segment of %d (0 base)", scan_number, int_array[0], n_segments ); aapm_status( eAAPM_WARN, aapm_log_string ); aapm_status( eAAPM_WARN, "Trying to salvage remaining contour data" ); /* TRY TO SALVAGE REMAINDER OF DATA */ action_state = eSCAN_NUM; break; } n_points = int_array[0]; cur_point = 0; action_state = eSTRUCT_COORD; /* ALLOCATE THE STRUCTURE LIST NODE */ if ( file->image.structure.contours == NULL ) { /* ALLOCATE HEAD OF LIST */ if ( (file->image.structure.contours = (structurelist_t *)calloc( (size_t)1, sizeof(structurelist_t))) == NULL ) { sprintf( aapm_log_string, "Error allocating memory for structure contour" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } contour = file->image.structure.contours; } else { /* ALLOCATE NEXT LINK IN CHAIN */ if ( (contour->next = (struct structurelist_t *)calloc( (size_t)1, sizeof(structurelist_t))) == NULL ) { sprintf( aapm_log_string, "Error allocating memory for structure contour" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } contour = (structurelist_t *)contour->next; } contour->scan_num = scan_number; contour->num_coords = n_points; /* ENSURE THAT THE NUMBER OF POINTS DOES NOT EXCEED THE DIRECTORY LIMIT */ if ( contour->num_coords > file->image.structure.max_pts_segment ) { sprintf( aapm_log_string, "# of points (%d) exceeds stated limit of %d pts/segment", contour->num_coords, file->image.structure.max_pts_segment ); aapm_status( eAAPM_WARN, aapm_log_string ); } /* ALLOCATE THE COORDINATE ARRAY */ if ( (contour->coords = (doublet_t *)malloc( sizeof(doublet_t) * n_points )) == NULL ) { sprintf( aapm_log_string, "Error allocating coordinate array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } break; case eSTRUCT_COORD: if ( (extract_floats( string, float_array, 20 )) != 3 ) { sprintf( aapm_log_string, "Error extracting coordinates from structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)block_data ); return( FAILURE ); } contour->coords[cur_point].x = float_array[0]; contour->coords[cur_point].y = float_array[1]; /* ONLY ASSIGN COORDINATE THE FIRST TIME THROUGH */ if ( cur_point == 0 ) contour->const_coord = float_array[2]; /* ENSURE THAT ALL CONTOURS FOR THIS SCAN HAVE THE SAME Z COORDINATE */ if ( cur_point == 0 ) { /* SET THE CONSTANT VALUE */ const_z = contour->const_coord; /* CHECK TO ENSURE THE CT SCAN NUMBER REFERENCED MATCHES THE Z COORDINATE */ if ( check_z( const_z, scan_number, p_case, &scan_z ) != SUCCESS ) { if ( mismatch == 0 ) { sprintf( aapm_log_string, "Z coord mismatch between scan #%d (%.2f) and %s (%.2f)", scan_number, scan_z, file->image.structure.struct_name, const_z ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Forcing contour to match the CT scan Z" ); aapm_status( eAAPM_ERROR, aapm_log_string ); } /* ASSUME THAT THE SCAN COORDINATE IS THE ONE TO USE */ contour->const_coord = scan_z; mismatch++; } } else { if ( const_z != float_array[2] ) { if ( mismatch < 2 ) { sprintf( aapm_log_string, "Inconsistent Z coordinates. Was: %.2f is now: %.2f for %s", const_z, float_array[2], file->image.structure.struct_name ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Forcing contour to match the CT scan Z" ); aapm_status( eAAPM_ERROR, aapm_log_string ); mismatch++; } else { /* JUST INCREMENT MISMATCH COUNT */ mismatch++; } } } cur_point++; if ( cur_point >= n_points ) { /* ENSURE THAT THE CONTOUR IS CLOSED */ if ( contour->coords[0].x != contour->coords[n_points-1].x || contour->coords[0].y != contour->coords[n_points-1].y ) { /* FLAG THE ERROR AND TRY TO FIX IT ARBITRARILY */ sprintf( aapm_log_string, "Contour not closed (%.2f, %.2f), (%.2f,%.2f)...closing", contour->coords[0].x, contour->coords[0].y, contour->coords[n_points-1].x, contour->coords[n_points-1].y ); aapm_status( eAAPM_WARN, aapm_log_string ); /* ADD ONE MORE COORDINATE TO THE ARRAY */ if ( (contour->coords = (doublet_t *)realloc( (void *)contour->coords, (size_t)( sizeof(doublet_t) * (n_points+1) ))) == NULL ) { sprintf( aapm_log_string, "Couldn't realloc contour array. Attempting to continue" ); aapm_status( eAAPM_ERROR, aapm_log_string ); } else { /* CLOSE THE CONTOUR */ contour->coords[n_points].x = contour->coords[0].x; contour->coords[n_points].y = contour->coords[0].y; n_points++; } } /* SET STATE FOR FURTHER PROCESSING */ if ( cur_segment < n_segments ) { cur_segment++; action_state = eNUM_POINTS; } else { /* REPORT ON ADDITIONAL MISMATCHES */ if ( mismatch > 2 ) { sprintf( aapm_log_string, "There were a total of %d additional Z coord mismatches", mismatch-2 ); aapm_status( eAAPM_ERROR, aapm_log_string ); } if ( scan_count < n_levels ) action_state = eSCAN_NUM; else /* FORCE TERMINATION OF PROCESSING */ offset = file->data_size + 1; } } break; } } /* SEND STRUCTURE DATA TO RTP SYSTEM FILE HANDLING ROUTINE */ retval = SUCCESS; if ( save_structures( p_case, file ) != SUCCESS ) { sprintf( aapm_log_string, "Error converting structure file in rtp format" ); aapm_status( eAAPM_ERROR, aapm_log_string ); retval = FAILURE; } /* FREE THE STRUCTURE DATA BLOCK */ free( (void *)block_data ); /* FREE THE LINKED STRUCTURE LIST */ contour = file->image.structure.contours; while( contour != NULL ) { free( (void *)contour->coords ); temp = (structurelist_t *)contour->next; free( (void *)contour ); contour = (structurelist_t *)temp; } return( retval ); } /******************* End of process_structures() **************************/ /* */ /***************************************************************************** process_dose() **************************************************************************** Functional Description: Processes dose files and calls routine to convert and save it in the RTP system format file. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int process_dose ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME CONTAINING DOSES */ FILE *fp; /* DOSE FILE STREAM POINTER */ int done; /* FLAG FOR COMPLETION OF DOSE FILE */ int state; /* STATE OF WHAT TO EXPECT FOR NEXT NUMERIC VALUE PULLED OUT OF DOSE FILE */ float array[20]; /* ARRAY OF FLOATING NUMBERS TO BE FILLED IN BY EXTRACTION ROUTINES */ int count; /* NUMBER OF NUMERIC VALUES PARSED FROM STRING READ FROM DOSE FILE */ int inum; /* LOOP COUNTER */ int index; /* OFFSET INTO DOSE MATRIX FOR NEXT VALUE TO BE PLACED */ int plane_num; /* NUMBER OF PLANE CURRENTLY BEING READ IN */ int num_per_plane; /* NUMBER OF DOSE POINTS PER PLANE */ #define dNUM_PLANES 0 #define dZCOORD 1 #define dDOSES 2 #define dDONE 3 /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_doses == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &fp, filename, tape->block_size, &file->image.dose.total_blocks, &file->data_size ) != SUCCESS ) { /* LET USER KNOW A PROBLEM OCCURRED */ sprintf( aapm_log_string, "Error opening dose file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALLOCATE A 3-D ARRAY FOR THE DOSES */ if ( (file->image.dose.doses = (float *)malloc( (size_t)(file->image.dose.num_horiz_pts * file->image.dose.num_vert_pts * file->image.dose.num_planes * sizeof(float)) )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for doses" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* ALLOCATE A DATA BLOCK FOR THE TAPE BLOCK DATA */ if ( (file->image.dose.data_block = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for dose block data" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* ALLOCATE ARRAY FOR THE PLANE POSITIONS */ if ( (file->image.dose.plane_coords = (float *)malloc((size_t)file->image.dose.num_planes * sizeof(float))) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for plane coordinates" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } /* SET UP THE COUNTERS */ file->image.dose.block_size = file->image.dose.offset = file->data_size; file->image.dose.cur_block = 0; num_per_plane = file->image.dose.num_vert_pts * file->image.dose.num_horiz_pts; /* PROCESS THE DOSE FILE AND READ IN ALL DOSE PLANES */ done = plane_num = index = 0; state = dNUM_PLANES; while ( done == 0 ) { /* GET A LINE FROM THE FILE */ if ( (count = read_aapm_dose_values( fp, &file->image.dose, array, 20 )) < 0 ) { sprintf( aapm_log_string, "Reading dose values Plane #%d, Row #%d, Col #%d", plane_num, ((index%num_per_plane)/file->image.dose.num_horiz_pts+1), ((index%num_per_plane)%file->image.dose.num_vert_pts+1)); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* HANDLE ALL NUMBERS READ */ for ( inum=0; inumimage.dose.num_planes ) { sprintf( aapm_log_string, "Data file inconsistent in plane count" ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Directory reports %d planes, file %d planes", file->image.dose.num_planes, (int)(array[inum] + 0.5) ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Will try to process data..." ); aapm_status( eAAPM_ERROR, aapm_log_string ); /* SET THE DIRECTORY COUNT TO THE FILE COUNT */ file->image.dose.num_planes = (int)(array[inum] + 0.5); /* ALLOCATE A 3-D ARRAY FOR THE DOSES */ if ( ((file->image.dose.doses = (float *)realloc( (void *)file->image.dose.doses, (size_t)(file->image.dose.num_horiz_pts * file->image.dose.num_vert_pts * file->image.dose.num_planes * sizeof(float)) )) == NULL ) || ((file->image.dose.plane_coords = (float *)realloc( (void *)file->image.dose.plane_coords, (size_t)(file->image.dose.num_planes * sizeof(float)))) == NULL )) { sprintf( aapm_log_string, "Error realloc'ing space for doses or plane coordinates" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( fp ); return( FAILURE ); } } state = dZCOORD; break; case dZCOORD: /* COORDINATE FOR THIS PLANE */ file->image.dose.plane_coords[plane_num] = array[inum]; plane_num++; state = dDOSES; break; case dDOSES: /* READ A DOSE VALUE */ file->image.dose.doses[index] = array[inum]; index++; if ( ( index % num_per_plane ) == 0 ) { if ( plane_num < file->image.dose.num_planes ) state = dZCOORD; else { done = 1; state = dDONE; } } break; case dDONE: /* I'M DONE, DO NOTHING */ default: break; } /* END OF SWITCH */ } /* END FOR FOR INUM LOOP */ } /* END OF WHILE LOOP */ /* SAVE THE DOSE */ if ( save_doses( p_case, file ) != SUCCESS ) { sprintf( aapm_log_string, "Error saving dose file in rtp format" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } return( SUCCESS ); } /******************* End of process_dose() *******************************/ /* */ /***************************************************************************** process_comment() **************************************************************************** Functional Description: Processes AAPM format comment files and dispatches control to routine to convert and save the data in RTP system format. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int process_comment ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME CONTAINING DOSES */ FILE *input; /* COMMENT FILE STREAM POINTER */ int done; /* FLAG FOR COMPLETION OF COMMENT FILE */ int total_blocks; /* NUMBER OF BLOCKS IN COMMENT FILE */ char string[MAX_LINE_LENGTH]; /* TEMPORARY TEXT STORAGE */ char *data_block; /* BLOCK OF MEMORY FOR TAPE BLOCK DATA */ int cur_block; /* CURRENT BLOCK NUMBER */ int offset; /* OFFSET IN BLOCK TO READ FROM */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_comments == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &input, filename, tape->block_size, &total_blocks, &file->data_size ) != SUCCESS ) { sprintf( aapm_log_string, "Error opening exchange comment file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* INITIALIZE SOME VALUES */ cur_block = done = offset = 0; /* ALLOCATE DATA BLOCK */ if ( (data_block = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for comment data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ IN THE FIRST COMMENT BLOCK */ if ( fread( (void *)data_block, (size_t)1, (size_t)file->data_size, input) != file->data_size ) { sprintf( aapm_log_string, "Error reading block #%d of comment text data", cur_block ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ UNTIL WE'RE DONE WITH FILE */ cur_block++; while ( done == 0 ) { /* GET A LINE FROM THE FILE */ while ( extract_line( data_block, &offset, file->data_size, string, 82 ) != SUCCESS && done == 0 ) { /* READ IN THE NEXT BUFFER IF OUT OF DATA AND MORE EXISTS */ if ( cur_block >= total_blocks ) { /* WE'RE DONE, WE'RE OUTA HERE */ fclose( input ); done = 1; } } /* END OF WHILE extract_line LOOP */ /* SAVE THE STRING INTO THE COMMENT STRUCTURE */ if ( done == 0 && add_comment_line( file, string ) != SUCCESS ) { /* SOME BIZARRE ERROR OCCURRED. LET USER KNOW */ sprintf( aapm_log_string, "Error storing comment line in memory" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } } /* END OF WHILE (done == 0) LOOP */ /* SAVE THE DATA AND RETURN */ return( save_comment( p_case, file )); } /******************* End of process_comment() **************************/ /* */ /***************************************************************************** add_comment_line() **************************************************************************** Functional Description: Puts the string into a linked list of strings for the comment file. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ static int add_comment_line ( exch_file_t *file, /* TAPE FILE NODE TO BE SAVED */ char *string /* STRING TO SAVE */ ) { static comment_line_t *current_ptr; /* CURRENT PTR VALUE FOR TRACKING LOCATION */ /* DETERMINE IF THE BASE OF THE LIST EXISTS YET */ if ( file->image.comment.line == NULL ) { /* CREATE BASE OF LINKED LIST */ if ( (file->image.comment.line = (comment_line_t *)calloc( (size_t)1, sizeof(comment_line_t))) == NULL ) { /* LET USER KNOW WE'RE OUT OF MEMORY */ sprintf( aapm_log_string, "Error allocating next comment line node memory" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* SET THE LOCAL STATIC POINTER EQUAL TO THIS ADDRESS */ current_ptr = file->image.comment.line; } else { /* ADD NEXT LINK IN THE CHAIN */ if ( (current_ptr->next = (struct comment_line_t *)calloc((size_t)1, sizeof(comment_line_t))) == NULL ) { /* AGAIN, WE'RE OUT OF MEMORY */ sprintf( aapm_log_string, "Error allocating next node for comment line" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* MOVE THE LOCAL POINTER */ current_ptr = (comment_line_t *)current_ptr->next; } /* DUPLICATE THE STRING */ if ( (current_ptr->string = dup_string( string )) == NULL ) { /* THE MEMORY PROBLEMS CONTINUE */ sprintf( aapm_log_string, "Error duplicating comment string" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALL IS WELL */ return( SUCCESS ); } /******************* End of add_comment_line() **************************/ /* */ /***************************************************************************** process_beam_geometry() **************************************************************************** Functional Description: Processes AAPM format beam geometry files and dispatches control to routine to convert and save the data in RTP system format. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ /* LOCAL DEFINITIONS FOR FLOW CONTROL */ #define sISOCENTER_X 0 #define sISOCENTER_Y 1 #define sISOCENTER_Z 2 #define sCOLLIMATOR_X1 3 #define sCOLLIMATOR_X2 4 #define sCOLLIMATOR_Y1 5 #define sCOLLIMATOR_Y2 6 #define sNUM_BLOCKS 7 #define sBLOCK_TYPE 8 #define sBLOCK_TRANSMISSION 9 #define sBLOCK_PAIR_COUNT 10 #define sBLOCK_COORD 11 #define sMLC_PAIR_COUNT 12 #define sLEAF_CENTER_COORD 13 #define sLEAF_THICK 14 #define sLEFT_INF_LEAF 15 #define sRIGHT_SUP_LEAF 16 #define sX_COORD 17 #define sY_COORD 18 int process_beam_geometry ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *cur_file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME CONTAINING DOSES */ FILE *input; /* COMMENT FILE STREAM POINTER */ int done; /* FLAG FOR COMPLETION OF BEAM FILE */ int total_blocks; /* NUMBER OF BLOCKS IN BEAM FILE */ char string[MAX_LINE_LENGTH]; /* TEMPORARY TEXT STORAGE */ char *data_block; /* BLOCK OF MEMORY FOR TAPE BLOCK DATA */ int cur_block; /* CURRENT BLOCK NUMBER */ int offset; /* OFFSET IN BLOCK TO READ FROM */ int action_state; /* ACTION TO BE TAKEN WITH NEXT DATA READ IN */ int int_array[10]; /* INTEGER ARRAY FOR DATA READ */ float float_array[20]; /* FLOAT ARRAY FOR DATA READ */ int count; /* NUMBER OF ARRAY VALUES READ */ int i; /* LOOP COUNTER */ beam_definition_t *beam_ptr; /* LOCAL POINTER */ block_t *block_ptr; /* LOCAL POINTER TO BLOCK DATA */ block_list_t *block_data_ptr; /* POINTER TO LINKED BLOCK LIST */ int point_count; /* NUMBER OF BLOCK POINT NEXT */ int read_size; /* NUMBER OF UNITS READ */ mlc_def_t *mlc_ptr; /* MLC POINTER */ int leaf_set; /* LEAF SET NUMBER BEING PROCESSED */ int leaf_count; /* COUNTER */ int coord_state; /* X OR Y COORDINATE EXPECTED FLAG */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_beams == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, cur_file->image_number ); if ( check_open( &input, filename, tape->block_size, &total_blocks, &cur_file->data_size ) != SUCCESS ) { sprintf( aapm_log_string, "Error opening exchange beam file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* INITIALIZE SOME VALUES */ cur_block = done = offset = 0; block_data_ptr = NULL; /* ALLOCATE DATA BLOCK */ if ( (data_block = (char *)malloc( (size_t)cur_file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for beam data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* ALLOCATE MEMORY FOR THE BEAM_DEFINTITION_T STRUCTURE */ if ( ( cur_file->image.beam_geometry.beam = beam_ptr = (beam_definition_t *)calloc( (size_t)1, sizeof( beam_definition_t ))) == NULL ) { sprintf( aapm_log_string, "Error allocating beam definition structure" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ ALL DATA IN */ if ( (read_size = fread( (void *)data_block, (size_t)1, (size_t)cur_file->data_size, input )) != cur_file->data_size ) { sprintf( aapm_log_string, "Error reading beam geometry file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", total_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, cur_file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); fclose( input ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( input ); action_state = sISOCENTER_X; /* PROCESS ALL DATA */ while( done == 0 ) { if ( extract_line( data_block, &offset, cur_file->data_size, string, MAX_LINE_LENGTH ) == FAILURE ) { sprintf( aapm_log_string, "Error reading data line from beam file " ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* SWITCH BASED ON INFO TO READ */ switch( action_state ) { case sISOCENTER_X: /* READ THE ISOCENTER VALUE(S) */ count = extract_floats( string, float_array, 10 ); switch( count ) { case 1: /* X VALUE ONLY */ beam_ptr->isocenter.x = float_array[0]; action_state = sISOCENTER_Y; break; case 2: /* X AND Y VALUES ONLY */ beam_ptr->isocenter.x = float_array[0]; beam_ptr->isocenter.y = float_array[1]; action_state = sISOCENTER_Z; break; case 3: /* ALL THREE VALUES */ beam_ptr->isocenter.x = float_array[0]; beam_ptr->isocenter.y = float_array[1]; beam_ptr->isocenter.z = float_array[2]; action_state = sCOLLIMATOR_X1; break; default: sprintf( aapm_log_string, "Incorrect number of isocenter values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } break; case sISOCENTER_Y: /* READ THE ISOCENTER VALUE(S) */ count = extract_floats( string, float_array, 10 ); switch( count ) { case 1: /* Y VALUE ONLY */ beam_ptr->isocenter.y = float_array[0]; action_state = sISOCENTER_Z; break; case 2: /* Y AND Z VALUES ONLY */ beam_ptr->isocenter.y = float_array[0]; beam_ptr->isocenter.z = float_array[1]; action_state = sCOLLIMATOR_X1; break; default: sprintf( aapm_log_string, "Incorrect number of isocenter values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } break; case sISOCENTER_Z: /* READ THE ISOCENTER VALUE(S) */ if ( (count = extract_floats( string, float_array, 10 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of isocenter values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } beam_ptr->isocenter.z = float_array[0]; action_state = sCOLLIMATOR_X1; break; case sCOLLIMATOR_X1: /* X COLLIMATOR SETTING */ count = extract_floats( string, float_array, 5 ); switch( count ) { case 1: /* ONLY 1 VALUE ON THIS LINE */ beam_ptr->collimator.x1 = float_array[0]; if ( cur_file->image.beam_geometry.collimator == eASYMMETRIC || cur_file->image.beam_geometry.collimator == eASYMMETRIC_X ) action_state = sCOLLIMATOR_X2; else { beam_ptr->collimator.x1 = beam_ptr->collimator.x2 = beam_ptr->collimator.x1 / 2.0; action_state = sCOLLIMATOR_Y1; } break; case 2: /* BOTH SIDES */ if ( cur_file->image.beam_geometry.collimator != eASYMMETRIC && cur_file->image.beam_geometry.collimator != eASYMMETRIC_X ) { sprintf( aapm_log_string, "Incorrect number of x collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } beam_ptr->collimator.x1 = float_array[0]; beam_ptr->collimator.x2 = float_array[1]; action_state = sCOLLIMATOR_Y1; break; default: sprintf( aapm_log_string, "Incorrect number of x collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } break; case sCOLLIMATOR_X2: /* X2 COLLIMATOR SETTING */ if ( (count = extract_floats( string, float_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of x collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } beam_ptr->collimator.x2 = float_array[0]; action_state = sCOLLIMATOR_Y1; break; case sCOLLIMATOR_Y1: /* Y COLLIMATOR SETTING */ count = extract_floats( string, float_array, 5 ); switch( count ) { case 1: /* INFERIOR SIDE ONLY */ beam_ptr->collimator.y1 = float_array[0]; if ( cur_file->image.beam_geometry.collimator == eASYMMETRIC || cur_file->image.beam_geometry.collimator == eASYMMETRIC_Y ) action_state = sCOLLIMATOR_Y2; else { beam_ptr->collimator.y1 = beam_ptr->collimator.y2 = beam_ptr->collimator.y1 / 2.0; /* SET STATE DEPENDING ON APERTURE TYPE */ switch( cur_file->image.beam_geometry.aperture ) { case eBLOCK_PORT: /* PORT IS DEFINED BY BLOCK */ action_state = sNUM_BLOCKS; break; case eCOLLIMATOR: /* PORT IS DEFINED BY COLLIMATORS */ done = 1; break; default: /* MUST BE MLC */ action_state = sMLC_PAIR_COUNT; leaf_set = -1; break; } } break; case 2: /* BOTH SIDES */ if ( cur_file->image.beam_geometry.collimator != eASYMMETRIC && cur_file->image.beam_geometry.collimator != eASYMMETRIC_Y ) { sprintf( aapm_log_string, "Incorrect number of y collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } beam_ptr->collimator.y1 = float_array[0]; beam_ptr->collimator.y2 = float_array[1]; /* SET STATE ACCORDING TO WHAT SHOULD BE NEXT */ switch( cur_file->image.beam_geometry.aperture ) { case eBLOCK_PORT: /* PORT IS DEFINED BY BLOCK */ action_state = sNUM_BLOCKS; break; case eCOLLIMATOR: /* PORT IS DEFINED BY COLLIMATORS */ done = 1; break; default: /* MUST BE MLC */ action_state = sMLC_PAIR_COUNT; leaf_set = -1; break; } break; default: sprintf( aapm_log_string, "Incorrect number of y collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } break; case sCOLLIMATOR_Y2: /* Y2 COLLIMATOR SETTING */ if ( (count = extract_floats( string, float_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of y collimator values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } beam_ptr->collimator.y2 = float_array[0]; /* SET STATE ACCORDING TO WHAT SHOULD BE NEXT */ switch( cur_file->image.beam_geometry.aperture ) { case eBLOCK_PORT: /* PORT IS DEFINED BY BLOCK */ action_state = sNUM_BLOCKS; break; case eCOLLIMATOR: /* PORT IS DEFINED BY COLLIMATORS */ done = 1; break; default: /* MUST BE MLC */ action_state = sMLC_PAIR_COUNT; leaf_set = -1; break; } break; case sNUM_BLOCKS: /* NUMBER OF BLOCK_CONTOURS */ /* ALLOCATE MEMORY FOR BLOCK STRUCTURE */ if ( (block_ptr = beam_ptr->aperture.ap_def.block = (block_t *)calloc( (size_t)1, sizeof( block_t ) )) == NULL ) { sprintf( aapm_log_string, "Error allocating block data structure " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* GET THE BLOCK COUNT */ if ( (count = extract_ints( string, int_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of block count values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SAVE NUMBER OF BLOCKS */ block_ptr->number_block_contours = int_array[0]; cur_block = 0; /* SET THE STATE FOR THE NEXT EXPECTED ENTRY, BLOCK COUNT OR DONE */ action_state = sBLOCK_TYPE; block_data_ptr = NULL; break; case sBLOCK_TYPE: /* BLOCK TYPE VALUE */ /* ALLOCATE MEMORY FOR BLOCK DATA STRUCTURE */ if ( block_data_ptr == NULL ) { if ( (block_data_ptr = (block_list_t *)calloc( (size_t)1, sizeof( block_list_t ) )) == NULL ) { sprintf( aapm_log_string, "Error allocating block data structure " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SET THE STRUCTURE POINTER */ block_ptr->blocks = block_data_ptr; } else /* ALLOCATE NEXT LINK IN LIST */ { if ( (block_data_ptr->next = (struct block_list_t *)calloc( (size_t)1, sizeof( block_list_t ) )) == NULL ) { sprintf( aapm_log_string, "Error allocating block data structure " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } block_data_ptr = (block_list_t *)block_data_ptr->next; } /* EXTRACT THE BLOCK TYPE */ if ( (count = extract_ints( string, int_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of block type values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SAVE BLOCK TYPE */ if ( int_array[0] == 0 ) block_data_ptr->block_typ = eAPERTURE; else block_data_ptr->block_typ = eBLOCK; /* SET THE STATE FOR THE NEXT EXPECTED ENTRY, BLOCK COUNT OR DONE */ action_state = sBLOCK_TRANSMISSION; break; case sBLOCK_TRANSMISSION: /* BLOCK TRANSMISSION VALUE */ if ( (count = extract_floats( string, float_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of block trans values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SAVE BLOCK TRANSMISSION */ block_data_ptr->transmission = float_array[0]; /* SET THE STATE FOR THE NEXT EXPECTED ENTRY, BLOCK COUNT OR DONE */ action_state = sBLOCK_PAIR_COUNT; break; case sBLOCK_PAIR_COUNT: /* BLOCK COORDINATE PAIR COUNT */ if ( (count = extract_ints( string, int_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of block point count values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SET THE POINT COUNT */ block_data_ptr->number_coords = int_array[0]; /* ALLOCATE MEMORY FOR BLOCK POINT DATA */ if ( (block_data_ptr->coords = (doublet_t *)calloc( (size_t)block_data_ptr->number_coords, sizeof( doublet_t ) )) == NULL ) { sprintf( aapm_log_string, "Error allocating memory for block coords " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SET THE STRUCTURE POINTER */ beam_ptr->aperture.ap_def.block = block_ptr; /* SET THE STATE FOR THE NEXT EXPECTED ENTRY, BLOCK COUNT OR DONE */ action_state = sBLOCK_COORD; /* SET STATE FOR X COORDINATE EXPECTED NEXT */ coord_state = sX_COORD; point_count = 0; break; case sBLOCK_COORD: /* BLOCK COORDINATE VALUE(S) */ if ( (count = extract_floats( string, float_array, 5 )) <= 0 ) { sprintf( aapm_log_string, "Error in reading block coordinates" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* COPY THE COORDINATES INTO THE APPROPRIATE PLACE */ for ( i=0; icoords[point_count].x = float_array[i]; coord_state = sY_COORD; } else { block_data_ptr->coords[point_count].y = float_array[i]; coord_state = sX_COORD; point_count++; } } /* SET THE STATE FOR THE NEXT EXPECTED ENTRY */ if ( point_count >= block_data_ptr->number_coords ) { /* INCREMENT THE BLOCK NUMBER TO BE WORKING ON */ cur_block++; /* SEE IF ANY MORE BLOCKS TO HANDLE */ if ( cur_block < block_ptr->number_block_contours ) action_state = sBLOCK_TYPE; else done = 1; } break; default: /* UNSUPPORTED TYPE (FOR NOW) */ sprintf( aapm_log_string, "Unsupported beam file data" ); aapm_status( eAAPM_ERROR, aapm_log_string ); break; case sMLC_PAIR_COUNT: /* EXTRACT THE NUMBER OF LEAFS */ if ( (count = extract_ints( string, int_array, 5 )) != 1 ) { sprintf( aapm_log_string, "Incorrect number of leaf count values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* SEE IF THE MLC STRUCTURES HAVE BEEN ALLOCATED */ if ( leaf_set < 0 ) { if ( (mlc_ptr = allocate_mlc( beam_ptr, cur_file, int_array[0] )) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc structure memory " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } leaf_set = 0; } mlc_ptr->number_leafs = int_array[0]; leaf_count = 0; action_state = sLEAF_CENTER_COORD; break; case sLEAF_CENTER_COORD: count = extract_floats( string, float_array, 20 ); if ( (count + leaf_count) > mlc_ptr->number_leafs ) { sprintf( aapm_log_string, "Incorrect number of leaf position values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } for ( i=0; ipos_value[leaf_count] = float_array[i]; leaf_count++; } /* SEE IF WE'RE DONE WITH THE POSITIONS STUFF */ if ( leaf_count >= mlc_ptr->number_leafs ) { leaf_count = 0; action_state = sLEAF_THICK; } break; case sLEAF_THICK: count = extract_floats( string, float_array, 20 ); if ( ( count + leaf_count) > mlc_ptr->number_leafs ) { sprintf( aapm_log_string, "Incorrect number of leaf thickness values" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } for ( i=0; ithick[leaf_count] = float_array[i]; leaf_count++; } /* SEE IF WE'RE DONE WITH THE POSITIONS STUFF */ if ( leaf_count >= mlc_ptr->number_leafs ) { action_state = sLEFT_INF_LEAF; leaf_count = 0; } break; case sLEFT_INF_LEAF: count = extract_floats( string, float_array, 20 ); switch( count ) { case 1: /* LEFT/INFERIOR LEAF POSITION */ mlc_ptr->extension1[leaf_count] = float_array[0]; action_state = sRIGHT_SUP_LEAF; break; case 2: /* LEFT/INFERIOR & RIGHT/SUP LEAF POSITION */ mlc_ptr->extension1[leaf_count] = float_array[0]; mlc_ptr->extension2[leaf_count] = float_array[1]; leaf_count++; if ( leaf_count >= mlc_ptr->number_leafs ) { if ( cur_file->image.beam_geometry.aperture == eMLC_XY_AXIS && leaf_set == 0 ) { mlc_ptr = beam_ptr->aperture.ap_def.mlc_xy->y_mlc_set; leaf_set++; action_state = sMLC_PAIR_COUNT; } else /* I'M DONE */ done = 1; } else action_state = sLEFT_INF_LEAF; break; default: sprintf( aapm_log_string, "Sender has chosen a very unkind format. I quit" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* END OF INF LEAF SWITCH */ break; case sRIGHT_SUP_LEAF: if ( (count = extract_floats( string, float_array, 20 )) != 1 ) { sprintf( aapm_log_string, "Sender has chosen a very unkind format. I quit" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } mlc_ptr->extension2[leaf_count] = float_array[1]; leaf_count++; action_state = sLEFT_INF_LEAF; if ( leaf_count >= mlc_ptr->number_leafs ) { if ( cur_file->image.beam_geometry.aperture == eMLC_XY_AXIS && leaf_set == 0 ) { mlc_ptr = beam_ptr->aperture.ap_def.mlc_xy->y_mlc_set; leaf_set++; action_state = sMLC_PAIR_COUNT; } else /* I'M DONE */ done = 1; } break; } /* END OF SWITCH */ } /* END OF WHILE */ /* FREE THE DATA BLOCK */ free( (void *)data_block ); /* SAVE THE DATA AND RETURN */ return( save_beam( p_case, cur_file )); } /******************* End of process_beam_geometry() ***********************/ /* */ /*********************************************************************** process_seed_geometry() ********************************************************************** Functional Description: Processes AAPM format seed geometry files and dispatches control to routine to convert and save the data in RTP system format. Returns SUCCESS or FAILURE on an error. *********************************************************************/ /* LOCAL DEFINITIONS FOR FLOW CONTROL */ #define sHEADER_LINE 0 #define sSEED_COORD 1 int process_seed_geometry ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* PATIENT CASE */ exch_file_t *cur_file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME */ FILE *input; /* COMMENT FILE STREAM POINTER */ int total_blocks; /* NUMBER OF BLOCKS IN SEED FILE */ char string[MAX_LINE_LENGTH]; /* TEMPORARY TEXT STORAGE */ char *data_block; /* BLOCK OF MEMORY FOR TAPE BLOCK */ int offset; /* OFFSET IN BLOCK TO READ FROM */ int action_state; /* ACTION TO BE TAKEN WITH NEXT DATA */ float float_array[3]; /* FLOAT ARRAY FOR DATA READ */ int count; /* NUMBER OF SEED COORDS READ */ seed_coord_ll_t *seed_ptr; /* LOCAL POINTER */ seed_coord_ll_t *seed_ptr1; /* LOCAL POINTER */ int read_size; /* NUMBER OF UNITS READ */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_seeds == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, cur_file->image_number ); if ( check_open( &input, filename, tape->block_size, &total_blocks, &cur_file->data_size ) != SUCCESS ) { sprintf( aapm_log_string, "Error opening exchange seed file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALLOCATE DATA BLOCK */ if ( (data_block = (char *)malloc( (size_t)cur_file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for seed data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ ALL DATA IN */ if ( (read_size = fread( (void *)data_block, (size_t)1, (size_t)cur_file->data_size, input )) != cur_file->data_size ) { sprintf( aapm_log_string, "Error reading seed geometry file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", total_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, cur_file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); fclose( input ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( input ); action_state = sHEADER_LINE; /* PROCESS THE SEED COORDINATES */ offset = 0; for(count=0; count < cur_file->image.seeddata.nseeds; ) { if ( extract_line( data_block, &offset, cur_file->data_size, string, MAX_LINE_LENGTH ) == FAILURE ) { sprintf(aapm_log_string,"Error reading data line from seed file"); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* SWITCH BASED ON INFO TO READ */ switch( action_state ) { case sHEADER_LINE: cur_file->image.seeddata.coords = NULL; /* Null the list */ action_state = sSEED_COORD; break; case sSEED_COORD: /* CREATE A SEED COORD LL NODE */ if ( (seed_ptr = calloc(1,sizeof(seed_coord_ll_t))) == NULL ) { sprintf(aapm_log_string,"Error allocating seed coord LL node"); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* GET THE SEED COORDS */ if( extract_floats( string, float_array, 3 ) != 3 ) { sprintf( aapm_log_string, "Illegal format in process_seed_geometry()"); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } seed_ptr->coord.x = float_array[0]; seed_ptr->coord.y = float_array[1]; seed_ptr->coord.z = float_array[2]; /* ADD THE NEW NODE TO THE END OF THE SEED COORD LL */ if(cur_file->image.seeddata.coords == NULL) { cur_file->image.seeddata.coords = seed_ptr; } else { seed_ptr1 = cur_file->image.seeddata.coords; while (seed_ptr1->next != NULL) seed_ptr1 = seed_ptr1->next; seed_ptr1->next = seed_ptr; } count++; /* increment the seed count */ break; } /* END OF SWITCH */ } /* END OF FOR */ /* FREE THE DATA BLOCK */ free( (void *)data_block ); /* SAVE THE DATA AND RETURN */ return( save_seed( p_case, cur_file )); } /*************** End of process_seed_geometry() ***********************/ /* */ /***************************************************************************** process_digital_film() **************************************************************************** Functional Description: Processes AAPM format digital film files and dispatches control to routine to convert and save the data in RTP system format. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int process_digital_film ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME CONTAINING FILM IMAGE */ FILE *input; /* COMMENT FILE STREAM POINTER */ int total_blocks; /* NUMBER OF BLOCKS IN FILM FILE */ int read_size; /* NUMBER OF BYTES READ FROM FILE */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_films == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &input, filename, tape->block_size, &total_blocks, &file->data_size ) != SUCCESS ) { sprintf( aapm_log_string, "Error opening exchange film file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALLOCATE AND READ IN THE DATA */ if ( (file->image.film.pixbuf = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for film data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)file->image.film.pixbuf, (size_t)1, (size_t)file->data_size, input )) != file->data_size ) { sprintf( aapm_log_string, "Error reading film file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", total_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)file->image.film.pixbuf ); fclose( input ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( input ); /* SAVE THE DATA AND RETURN */ return( save_film( p_case, file )); } /******************* End of process_digital_film() ***********************/ /* */ /***************************************************************************** process_dvh() **************************************************************************** Functional Description: Processes AAPM format DVH files and dispatches control to routine to convert and save the data in RTP system format. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ #define EPSILON 0.001 int process_dvh ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ case_t *p_case, /* CURRENT CASE */ exch_file_t *file /* EXCHANGE FILE DIRECTORY ENTRY */ ) { char filename[PATH_MAX]; /* FILE NAME CONTAINING DVH DATA */ FILE *input; /* COMMENT FILE STREAM POINTER */ int total_blocks; /* NUMBER OF BLOCKS IN DVH FILE */ char string[MAX_LINE_LENGTH]; /* TEMPORARY TEXT STORAGE */ char *data_block; /* BLOCK OF MEMORY FOR TAPE BLOCK DATA */ int offset; /* OFFSET IN BLOCK TO READ FROM */ float float_array[20]; /* FLOAT ARRAY TO READ DATA INTO */ int point_count; /* NUMBER OF POINTS PROCESSED */ int i; /* LOOP COUNTER */ int read_size; /* NUMBER OF UNITS READ */ int count; /* NUMBER OF VALUES EXTRACTED FROM STRING */ float dose_delta, cur_delta; /* ADJACENT DOSE BIN DIFFERENCES */ float min_delta, max_delta; /* BRACKETING DOSE BIN VALUES */ int first_delta; /* FLAG FOR DOSE BIN IRREGULARITY COUNT */ /* ONLY PROCESS IF FLAG IS SET */ if ( p_case->site_data.process_flags.do_dvhs == 0 ) return( SUCCESS ); /* ENSURE THAT FILE EXISTS AND IS THE CORRECT SIZE */ sprintf( filename, "%s/aapm%04d", tape->path, file->image_number ); if ( check_open( &input, filename, tape->block_size, &total_blocks, &file->data_size ) != SUCCESS ) { sprintf( aapm_log_string, "Error opening exchange dvh file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* INITIALIZE SOME VALUES */ offset = 0; /* ALLOCATE DATA BLOCK */ if ( (data_block = (char *)malloc( (size_t)file->data_size )) == NULL ) { sprintf( aapm_log_string, "Error malloc'ing space for comment data blocks" ); aapm_status( eAAPM_ERROR, aapm_log_string ); fclose( input ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)data_block, (size_t)1, (size_t)file->data_size, input )) != file->data_size ) { sprintf( aapm_log_string, "Error reading structure file: %s", filename ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Did not read %d blocks of data", total_blocks ); aapm_status( eAAPM_ERROR, aapm_log_string ); sprintf( aapm_log_string, "Read %d bytes of total %d data bytes", read_size, file->data_size ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); fclose( input ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( input ); /* ALLOCATE THE MEMORY FOR THE DVH DATA */ if ( (file->image.dvh.dvh_data = (doublet_t *)malloc( sizeof( doublet_t ) * file->image.dvh.number_of_pairs )) == NULL ) { sprintf( aapm_log_string, "Error allocating dvh data block memory" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); return( FAILURE ); } /* READ IN ALL PAIRS */ point_count = 0; while( point_count < file->image.dvh.number_of_pairs ) { if ( extract_line( data_block, &offset, file->data_size, string, MAX_LINE_LENGTH ) == FAILURE ) { sprintf( aapm_log_string, "Error extracting data out of dvh data buffer " ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); free( (void *)file->image.dvh.dvh_data ); return( FAILURE ); } /* EXTRACT THE VALUES AND SKIP BLANK LINES */ if ( strlen( string ) == 0 || (count = extract_floats( string, float_array, 20 )) == 0 ) continue; /* ENSURE THAT AN EVEN NUMBER OF VALUES READ */ if ( (count % 2) != 0 ) { sprintf( aapm_log_string, "Odd number of dvh parameters read" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)data_block ); free( (void *)file->image.dvh.dvh_data ); return( FAILURE ); } /* PROCESS ALL ENTRIES READ IN */ for ( i=0; iimage.dvh.dvh_data[point_count].x = float_array[i]; file->image.dvh.dvh_data[point_count].y = float_array[i+1]; /* DETERMINE IF DOSE BIN DELTA IS CONSTANT */ if ( point_count == 1 ) { /* DETERMINE DELTA FOR FIRST PAIR */ dose_delta = file->image.dvh.dvh_data[point_count].x - file->image.dvh.dvh_data[point_count-1].x; min_delta = dose_delta - EPSILON; max_delta = dose_delta + EPSILON; first_delta = 0; } else { if ( point_count > 1 ) { /* CHECK THE DELTA ON THIS LAST PAIR */ cur_delta = file->image.dvh.dvh_data[point_count].x - file->image.dvh.dvh_data[point_count-1].x; if ( cur_delta < min_delta || cur_delta > max_delta ) { if ( first_delta == 0 ) { first_delta++; /* THIS DATA IS INCONSISTENT */ sprintf( aapm_log_string, "Inconsistent dose bins may cause problems. Std Bin %.3f, Bin #%d %.3f", dose_delta, point_count+1, cur_delta ); aapm_status( eAAPM_WARN, aapm_log_string ); } else first_delta++; } } } point_count++; } } if ( first_delta > 2 ) { sprintf( aapm_log_string, "There were %d more inconsistent dose bin sizes", first_delta-1 ); aapm_status( eAAPM_WARN, aapm_log_string ); } /* free the data block */ free( (void *)data_block ); /* SAVE THE DATA AND RETURN */ return( save_dvh( p_case, file )); } /******************* End of process_dvh() ********************************/ /* */ /***************************************************************************** allocate_mlc() **************************************************************************** Functional Description: Allocates memory required for mlc data structures depending upon the mlc type (eMLC_X_AXIS, eMLC_Y_AXIS, or eMLC_XY_AXIS). Returns SUCCESS or FAILURE on an error. ***************************************************************************/ static mlc_def_t *allocate_mlc ( beam_definition_t *beam_ptr, /* POINTER TO BEAM STRUCTURE */ exch_file_t *cur_file, /* EXCHANGE FILE DIRECTORY ENTRY */ int number_of_leafs /* NUMBER OF LEAFS IN THIS MLC */ ) { mlc_def_t *mlc_ptr; /* POINTER TO ALLOCATED STRUCTURE */ /* ALLOCATE THE STRUCTURES FOR THE MLC DATA */ switch( cur_file->image.beam_geometry.aperture ) { case eMLC_X_AXIS: case eMLC_Y_AXIS: if ( (mlc_ptr = beam_ptr->aperture.ap_def.mlc = (mlc_def_t *)calloc( (size_t)1, sizeof( mlc_def_t ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc struct" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( NULL ); } /* ALLOCATE THE LEAF SPACE */ if ( allocate_leafs( mlc_ptr, number_of_leafs ) != SUCCESS ) { sprintf( aapm_log_string, "Error allocating leaf storage" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr ); return( NULL ); } break; case eMLC_XY_AXIS: /* ALLOCATE THE POINTER TO THE TWIN MLC INFORMATION */ if ( (beam_ptr->aperture.ap_def.mlc_xy = (mlc_xy_t *)calloc( (size_t)1, sizeof( mlc_xy_t ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc_xy struct" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( NULL ); } /* ALLOCATE MEMORY FOR THE X MLC INFORMATION */ if ( (mlc_ptr = beam_ptr->aperture.ap_def.mlc_xy->x_mlc_set = (mlc_def_t *)calloc( (size_t)1, sizeof( mlc_def_t ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc_x struct" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( NULL ); } /* ALLOCATE THE X LEAF SPACE */ if ( allocate_leafs( mlc_ptr, number_of_leafs ) != SUCCESS ) { sprintf( aapm_log_string, "Error allocating x leaf storage" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr ); return( NULL ); } /* ALLOCATE MEMORY FOR THE Y MLC INFORMATION */ if ( (beam_ptr->aperture.ap_def.mlc_xy->y_mlc_set = (mlc_def_t *)calloc( (size_t)1, sizeof( mlc_def_t ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc_y struct" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr ); return( NULL ); } /* ALLOCATE THE Y LEAF SPACE */ if ( allocate_leafs( beam_ptr->aperture.ap_def.mlc_xy->y_mlc_set, number_of_leafs ) != SUCCESS ) { sprintf( aapm_log_string, "Error allocating y leaf storage" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr ); return( NULL ); } break; /* catch unhandled cases */ case eBLOCK_PORT: case eCOLLIMATOR: case eUNDEF_APERTURE: break; } /* RETURN THE POINTER TO THE ALLOCATED MEMORY */ return( mlc_ptr ); } /************************** End of allocate_mlc() *************************/ /* */ /***************************************************************************** allocate_leafs() **************************************************************************** Functional Description: Allocates memory required for mlc data structures depending upon the mlc type (eMLC_X_AXIS, eMLC_Y_AXIS, or eMLC_XY_AXIS). Returns SUCCESS or FAILURE on an error. ***************************************************************************/ static int allocate_leafs ( mlc_def_t *mlc_ptr, /* MLC POINTER */ int number_of_leafs /* NUMBER OF LEAFS IN THIS MLC */ ) { /* ALLOCATE THE MEMORY FOR THE CENTER COORDINATES */ if ( (mlc_ptr->pos_value = (float *)calloc( (size_t)number_of_leafs, sizeof( float ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc position array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); return( FAILURE ); } /* ALLOCATE THE MEMORY FOR THE EXTENSION 1 VALUES */ if ( (mlc_ptr->extension1 = (float *)calloc( (size_t)number_of_leafs, sizeof( float ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc extension 1 array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr->pos_value ); return( FAILURE ); } /* ALLOCATE THE MEMORY FOR THE EXTENSION 2 VALUES */ if ( (mlc_ptr->extension2 = (float *)calloc( (size_t)number_of_leafs, sizeof( float ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc extension 2 array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr->extension1 ); free( (void *)mlc_ptr->pos_value ); return( FAILURE ); } /* ALLOCATE THE MEMORY FOR THE THICKNESS VALUES */ if ( (mlc_ptr->thick = (float *)calloc( (size_t)number_of_leafs, sizeof( float ))) == NULL ) { sprintf( aapm_log_string, "Error allocating mlc thickness array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); free( (void *)mlc_ptr->extension2 ); free( (void *)mlc_ptr->extension1 ); free( (void *)mlc_ptr->pos_value ); return( FAILURE ); } /* EVERYTHING WENT AS PLANNED */ return( SUCCESS ); } /************************** End of allocate_leafs() ***********************/ /* */ /***************************************************************************** check_z() **************************************************************************** Functional Description: Walks the links of the CT chain (if it is contained in file set) to verify that the Z value for the scan (scan number) matches the Z coordinate of the contours attributed to that coordinate. Returns SUCCESS or FAILURE on an error. This routine only supports a single case file set. ***************************************************************************/ static int check_z ( float const_z, /* CONTOUR Z COORDINATE */ int scan_num, /* SCAN NUMBER */ case_t *p_case, /* LINKED LIST OF PATIENT FILES */ float *scan_z /* Z COORDINATE OF SCAN NUMBER RETURNED */ ) { exch_file_t *tmp_ptr; /* LINKED LIST WALKING POINTER */ static int num_cts = 0; /* NUMBER OF SCANS SET ONLY IF MATCH NOT FOUND FOR SPECIFIC SCAN NUMBER */ static int scan_exist = TRUE; /* POINTER TO FIRST SCAN, NULL IF NONE */ static float *ct_positions; /* ARRAY OF CT SCAN POSITIONS */ static exch_file_t *first_ct = NULL; /* POINTER TO FIRST CT SCAN LINK */ int i; /* LOOP COUNTER */ int expect; /* LOGICAL (WHAT'S NEXT) INDICATOR */ float z1, z2; /* COORDINATES FOR FIRST TWO CT SCANS */ /* LOCAL DEFINITIONS FOR CT SCANS INTERSPERSED WITH OTHER FILES */ #define A_ANYTHING 0 #define A_CTSCAN 1 #define A_NO_CTSCAN 2 /* COUNT NUMBER OF CT SCANS IF THIS IS FIRST CALL */ if ( scan_exist == FALSE ) return( SUCCESS ); if ( scan_exist == TRUE && num_cts == 0 ) { /* DEVELOP LIST OF CT SCAN COORDINATES */ tmp_ptr = p_case->head_file; expect = A_ANYTHING; while( tmp_ptr != NULL ) { /* SEE IF THIS IS A CT SCAN NODE */ if ( tmp_ptr->image_flag == eCTSCAN ) { /* INCREMENT NUMBER OF SCANS */ num_cts += 1; scan_exist = TRUE; if ( first_ct == NULL ) { first_ct = tmp_ptr; /* SET FLAG TO INDICATE THAT WE SHOULD HAVE AN UNINTERUPTED CHAIN OF CT IMAGES */ expect = A_CTSCAN; } } tmp_ptr = (exch_file_t *)tmp_ptr->next; if ( tmp_ptr == NULL || tmp_ptr->image_flag != eCTSCAN ) { switch( expect ) { case A_CTSCAN: /* ANY FILE TYPE IS OK HERE AFTER COMPLETING CT CHAIN */ expect = A_NO_CTSCAN; break; case A_NO_CTSCAN: /* KEEP GOING. ALL IS WELL, SO FAR */ case A_ANYTHING: break; } } else { /* ENSURE THAT CT SCANS ARE ALLOWED */ if ( expect == A_NO_CTSCAN ) { /* CT SCAN FILES HAVE OTHER FILES INAPPROPRIATELY INTERSPERSED */ sprintf( aapm_log_string, "CT Scan files interspersed with other file types" ); aapm_status( eAAPM_ERROR, aapm_log_string ); num_cts = 0; scan_exist = FALSE; return( FAILURE ); } } } /* SEE IF ANY SCANS WERE FOUND */ if ( num_cts == 0 ) { scan_exist = FALSE; /* REPORT THIS SHORTCOMING IN THE DATA SET */ sprintf( aapm_log_string, "No CT scans in set. Assuming contours are correct in position" ); aapm_status( eAAPM_WARN, aapm_log_string ); return( SUCCESS ); } /* ALLOCATE ARRAY FOR CT SCAN POSITIONS */ if ( (ct_positions = (float *)malloc( (size_t)num_cts * sizeof( float ))) == NULL ) { sprintf( aapm_log_string, "Failed allocating CT scan position array" ); aapm_status( eAAPM_ERROR, aapm_log_string ); num_cts = 0; scan_exist = FALSE; return( FAILURE ); } /* FILL THE ARRAY IN THE ORDER BASED ON THE DIRECTION OF THE INCREASING Z COORDINATE */ z1 = first_ct->image.ctscan.z_value; tmp_ptr = (exch_file_t *)first_ct->next; z2 = tmp_ptr->image.ctscan.z_value; /* RESET TMP_PTR */ tmp_ptr = first_ct; if ( z1 > z2 ) { /* SCANS ARE REVERSED. REPORT PROBLEM AND REVERSE THE ORDER OF COORDINATES */ sprintf( aapm_log_string, "CT scan order appears reversed. Attempting to correct." ); aapm_status( eAAPM_ERROR, aapm_log_string ); for ( i=(num_cts - 1); i > -1; i-- ) { /* SET THE COORDINATE */ ct_positions[i] = tmp_ptr->image.ctscan.z_value; tmp_ptr = (exch_file_t *)tmp_ptr->next; } } else { /* USE INCOMING ORDER */ for ( i=0; iimage.ctscan.z_value; tmp_ptr = (exch_file_t *)tmp_ptr->next; } } } /* SEE IF THE COORDINATE FOR THE DESIRED SCAN NUMBER MATCHES */ *scan_z = ct_positions[scan_num-1]; if ( *scan_z == const_z ) return( SUCCESS ); else return( FAILURE ); } /*************************** end of check_z() ******************************/ /************************* End of process_exch.c ***************************/