#include "StdAfx.h" #include "MA_Voxel_Coding.h" // ---------------------------------------------------------------------------------------- // RecurseOnAllNeighbors // // Description: Given a function pointer and a starting location, this will recurse to // all of the connected voxels of the starting point that meet criteria // specified in the TODO function. // // functionToDoPtr: Should return TRUE if provided neighbor coordinate needs to be recursed on, // FALSE if nothing more should be done with it. Note that 'pz' etc are // previous coordinates (where neighbor is encountered from). // // NOTE: 'recursion_queue' is allocated at MA creation to avoid memory reallocation on multiple calls // There is potential for a single queue to be used by different recursions if it was last item // in queue for one of them, but since it is an empty queue, and will be empty at end, there // shouldn't be any conflicts. // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::recurseOnAllNeighbors( Vect3usi &start_coord, InnerOpPtr functionToDoPtr ) { char dz, dy, dx, xl, xg, yl, yg, zl, zg; Vect3usi cur_coord = start_coord; Vect3usi nxt_coord = start_coord; // Find first available preallocated queue unsigned int current_group = 0; GroupedListNode<int,Vect3usi> *current_group_ptr = &(recursion_queue->getGroup( current_group ))->item; while ( current_group_ptr->list_ptr->getSize() > 0 ) { current_group_ptr = &(recursion_queue->getGroup( ++current_group ))->item; } LinkedList<Vect3usi> *coordinate_queue_ptr = current_group_ptr->list_ptr; // Insert starting point into coordinate_queue_ptr coordinate_queue_ptr->insertAtStart( coordinate_queue_ptr->getNewNode() ); (coordinate_queue_ptr->getHeadPtr())->item = cur_coord; // Perform function on starting spot, doesn't matter if it fails or not (this->*functionToDoPtr)(cur_coord, nxt_coord); // Now we will iterate through coordinate_queue_ptr until it is empty while ( coordinate_queue_ptr->getSize() > 0 ) { // Grab top item from queue cur_coord = (coordinate_queue_ptr->getHeadPtr())->item; coordinate_queue_ptr->removeHeadNode( ); // Boundary check xl=-1; xg=1; yl=-1; yg=1; zl=-1; zg=1; if (cur_coord.x < 1) xl = 0; if (cur_coord.y < 1) yl = 0; if (cur_coord.z < 1) zl = 0; if (cur_coord.x > boundary_cube->wX-2) xg = 0; if (cur_coord.y > boundary_cube->wY-2) yg = 0; if (cur_coord.z > boundary_cube->wZ-2) zg = 0; // Check if any neighbors have not been erased yet for (dz = zl; dz <= zg; dz++) { for (dy = yl; dy <= yg; dy++) for (dx = xl; dx <= xg; dx++) { nxt_coord.from_zyx( cur_coord.z+dz, cur_coord.y+dy, cur_coord.x+dx ); // Call work function if ( (this->*functionToDoPtr)(cur_coord, nxt_coord) ) { // Insert at end of coordinate_queue_ptr if 'true' returned coordinate_queue_ptr->insertAtEnd( coordinate_queue_ptr->getNewNode() ); (coordinate_queue_ptr->getTailPtr())->item = nxt_coord; } } } } } // ---------------------------------------------------------------------------------------- // RecurseOnFaceNeighbors // // Description: Given a function pointer and a starting location, this will recurse to // all of FACE connected voxels of the starting point that meet criteria // specified in the functionToDoPtr function. // // functionToDoPtr: Should return TRUE if provided neighbor coordinate needs to be recursed on, // FALSE if nothing more should be done with it. Note that 'pz' etc are // previous coordinates (where neighbor is encountered from). // // NOTE: 'coordinate_queue_ptr' is allocated at MA creation to avoid memory reallocation on multiple calls // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::recurseOnFaceNeighbors( Vect3usi &start_coord, InnerOpPtr functionToDoPtr ) { char i; Vect3usi cur_coord = start_coord; Vect3usi nxt_coord = start_coord; // Find first available preallocated queue unsigned int current_group = 0; GroupedListNode<int,Vect3usi> *current_group_ptr = &(recursion_queue->getGroup( current_group ))->item; while ( current_group_ptr->list_ptr->getSize() > 0 ) { current_group_ptr = &(recursion_queue->getGroup( ++current_group ))->item; } LinkedList<Vect3usi> *coordinate_queue_ptr = current_group_ptr->list_ptr; // Insert starting point into coordinate_queue_ptr coordinate_queue_ptr->insertAtStart( coordinate_queue_ptr->getNewNode() ); (coordinate_queue_ptr->getHeadPtr())->item = cur_coord; // Perform function on starting spot, doesn't matter if it fails or not (this->*functionToDoPtr)(cur_coord, nxt_coord); // Now we will iterate through coordinate_queue_ptr until it is empty while ( coordinate_queue_ptr->getSize() > 0 ) { // Grab head coordinate from queue cur_coord = (coordinate_queue_ptr->getHeadPtr())->item; coordinate_queue_ptr->removeHeadNode( ); nxt_coord = cur_coord; // For all 6 face neighbors for ( i = 0; i < 6; i++ ) { if ( !get_zyx_neigh_6dir(i, nxt_coord, boundary_cube->dimensions) ) { // Skip this iteration if out of bounds. continue; } // Call work function if ( (this->*functionToDoPtr)(cur_coord, nxt_coord) ) { // Insert at end of coordinate_queue_ptr if 'true' returned coordinate_queue_ptr->insertAtEnd( coordinate_queue_ptr->getNewNode() ); (coordinate_queue_ptr->getTailPtr())->item = nxt_coord; } } } } // ---------------------------------------------------------------------------------------- // checkForMedialAxisNeighbors() // // Description - Returns TRUE if any of the 6 neighbors of provided coordinate have // a value of 'ss_medial_path' in SS_cube. Otherwise FALSE is returned. // ---------------------------------------------------------------------------------------- bool MA_VoxelCoding::hasMedialAxisNeighbors( Vect3usi &around_this_coord, Vect3usi &nearest_to ) { Vect3usi cur_coord = around_this_coord, nearest_coord; unsigned int nearest_dist = 0xFFFFFFFF; // Check if any neighbors have not been erased yet for (char j = 0; j < 6; j++) { if ( get_zyx_neigh_6dir(j, cur_coord, boundary_cube->dimensions) ) { if ( SS_cube->datac(cur_coord) == ss_medial_path ) { // Found one! if ( cur_coord.get_dist_2_to(nearest_to) < nearest_dist ) { nearest_dist = cur_coord.get_dist_2_to( nearest_to ); nearest_coord = cur_coord; } } } } if ( nearest_dist < 0xFFFFFFFF ) { around_this_coord = nearest_coord; return true; } else { return false; } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::markPathInCube(LinkedList<PathNode> *path_ptr, DS_1b_cube *cube_to_mark_in, bool mark_val) { LinkedListNode<PathNode> *cur_node_ptr = path_ptr->getHeadPtr(); while ( cur_node_ptr ) { if ( cur_node_ptr->item.type == COORD_NODE ) { if ( mark_val ) { cube_to_mark_in->set_spot_1( cur_node_ptr->item.coordinate ); } else { cube_to_mark_in->set_spot_0( cur_node_ptr->item.coordinate ); } } cur_node_ptr = cur_node_ptr->next; } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::markPathInSSCube( LinkedList<PathNode> *path_ptr, ss_t mark_value ) { LinkedListNode<PathNode> *cur_node_ptr = path_ptr->getHeadPtr(); while ( cur_node_ptr ) { if ( cur_node_ptr->item.type == COORD_NODE ) { SS_cube->datac( cur_node_ptr->item.coordinate, mark_value ); } cur_node_ptr = cur_node_ptr->next; } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::removeCoordinateFromList( LinkedList<Vect3usi> *list_ptr, Vect3usi &coordinate ) { LinkedListNode<Vect3usi> *cur_coord_node_ptr = list_ptr->getHeadPtr(); LinkedListNode<Vect3usi> *tmp_coord_node_ptr = list_ptr->getHeadPtr(); while ( cur_coord_node_ptr ) { if ( cur_coord_node_ptr->item == coordinate ) { tmp_coord_node_ptr = cur_coord_node_ptr->next; list_ptr->removeNode( cur_coord_node_ptr ); cur_coord_node_ptr = tmp_coord_node_ptr; } else { cur_coord_node_ptr = cur_coord_node_ptr->next; } } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::moveOffOfMedialAxis( Vect3usi &coordinate ) { ss_t min_ss = ss_medial_path; Vect3usi cur_coord = coordinate; for ( char i = 0; i <= 6; i++ ) { if ( (get_zyx_neigh_6dir(i, cur_coord, boundary_cube->dimensions)) && (!boundary_cube->get_spot(cur_coord)) && (SS_cube->datac(cur_coord) < min_ss) && (SS_cube->datac(cur_coord) > 0) ) { min_ss = SS_cube->datac(cur_coord); coordinate = cur_coord; } } } // ---------------------------------------------------------------------------------------- // fatalErrorDump // // Description - Writes out to file any central data structures, and crashes (meant // for debugging purposes only) if 'is_fatal' true. // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::doFullDump( bool is_fatal ) { char out_name[MAX_FILE_STR_LEN]; sprintf( out_name, "%s_DUMP_v%d_p%d_SS_cube", result_file_prefix, current_volume_num, current_medial_path_num ); SS_cube->writeToFile( out_name ); sprintf( out_name, "%s_DUMP_v%d_p%d_CL_cube", result_file_prefix, current_volume_num, current_medial_path_num ); CL_cube->writeToFile( out_name ); sprintf( out_name, "%s_DUMP_v%d_p%d_BS_cube", result_file_prefix, current_volume_num, current_medial_path_num ); BS_cube->writeToFile( out_name ); for ( int i = 0; i < TOTAL_MARK_CUBES; i++ ) { sprintf( out_name, "%s_DUMP_v%d_p%d_MARK[%d]_cube", result_file_prefix, current_volume_num, current_medial_path_num, i ); MARK_cubes[i]->writeToFile( out_name, true ); } if ( is_fatal ) { exit(1); } }