#include "StdAfx.h" #include "MA_Voxel_Coding.h" // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::generateFullSS( ) { LinkedList<Vect3usi> *max_bs_list = new LinkedList<Vect3usi>( 50 ); char prog_desc_txt[512]; dt_ret_code dt_status; Vect3usi rp_point; Vect3usi last_scan_pt(0, 0, 0); progress_bar_ptr->SetRange( 0, CL_cube->wZ ); progress_bar_ptr->SetPos( 0 ); // Find a BS maximum for each independent porous volume progress_win_ptr->SetWindowText("SS Transform: Finding all sub-volumes BS max points..."); MARK_cubes[IN_QUEUE]->clear(); while ( findNextStartingPt( last_scan_pt, rp_point ) ) { progress_bar_ptr->SetPos( last_scan_pt.z ); max_bs_list->insertAtEnd( max_bs_list->getNewNode() ); max_bs_list->getTailPtr()->item = rp_point; } progress_bar_ptr->SetRange( 0, (short)max_bs_list->getSize() ); progress_bar_ptr->SetPos( 0 ); progress_bar_ptr->SetStep( 1 ); write_to_log("MA_VoxelCoding::generateFullSS - Found %d independent sub-volumes, now doing SS Xfrm on each.", max_bs_list->getSize()); sprintf(prog_desc_txt, "SS Transform: Found %d sub-volumes, now performing SS transform on each...", max_bs_list->getSize()); progress_win_ptr->SetWindowText( prog_desc_txt ); // In case caching is used, transfer all memory from BS cube to SS cube for the transform BS_cube->resizeCacheBuffer( 0 ); SS_cube->resizeCacheBuffer( memory_limit_total_bytes ); // Initialize SS cube SS_Xfrm->initXfrmCube( SS_cube ); // Generate SS fields while we still have RP points while ( max_bs_list->getSize() > 0 ) { // Grab next volumes BS max coordinate rp_point = (max_bs_list->getHeadPtr())->item; max_bs_list->removeNode( max_bs_list->getHeadPtr() ); // Generate the SS field in current pore volume dt_status = SS_Xfrm->runSS( SS_cube, rp_point, DT_FACE_ONLY ); if ( dt_status != DT_NO_ERROR ) { write_to_log( "MA_VoxelCoding::generateFullSS - FATAL ERROR - could not create SS field, error code %d", dt_status ); doFullDump( MA_CRASH_ON_FATAL_ERROR ); } // Increment volume count, this also prevents re-initializing SS cube ++number_of_volumes; // If we are using the max BS for start point, we can now continue to the next field if ( run_options & MA_USE_MAX_BS_FOR_RP ) { continue; } // Erase the SS field, and repeat in reverse. SS_Xfrm->eraseSS( SS_cube, rp_point, SS_cube->datac(rp_point), DT_FACE_ONLY ); dt_status = SS_Xfrm->runSS( SS_cube, rp_point, DT_FACE_ONLY ); if ( dt_status != DT_NO_ERROR ) { write_to_log( "MA_VoxelCoding::generateFullSS - FATAL ERROR - could not create furthest SS field, error code %d", dt_status ); doFullDump( MA_CRASH_ON_FATAL_ERROR ); } // Update progress bars printf(prog_desc_txt, "SS Transform: Found %d sub-volumes left for SS transformation...", max_bs_list->getSize()); progress_win_ptr->SetWindowText( prog_desc_txt ); progress_bar_ptr->StepIt(); } delete max_bs_list; } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- //returns false if we are done bool MA_VoxelCoding::findNextStartingPt( Vect3usi &begin_scan_pt, Vect3usi &ret_start_pt ) { // Find largest available BS for ( ; begin_scan_pt.z < boundary_cube->wZ; begin_scan_pt.z++ ) { for ( ; begin_scan_pt.y < boundary_cube->wY; begin_scan_pt.y++ ) { for ( ; begin_scan_pt.x < boundary_cube->wX; begin_scan_pt.x++ ) { // Make sure spot is a pore, and hasn't been traveled on yet if ( (!boundary_cube->get_spot(begin_scan_pt)) && (!MARK_cubes[IN_QUEUE]->get_spot(begin_scan_pt)) ) { // Setup recursion values, and then search pore for it's max BS coordinate current_max_bs_coord = begin_scan_pt; current_max_bs_value = BS_cube->datac( begin_scan_pt ); recurseOnFaceNeighbors( begin_scan_pt, &MA_VoxelCoding::findMaxBSInVolume ); ret_start_pt = current_max_bs_coord; return true; } } begin_scan_pt.x = 0; } begin_scan_pt.y = 0; } // If we make it here, no more new volumes were found return false; } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- bool MA_VoxelCoding::findMaxBSInVolume( Vect3usi &, Vect3usi &nxt_coord ) { // If spot is a PORE and is not yet initialized, see if it is bigger than current max if ( (!boundary_cube->get_spot(nxt_coord)) && (!MARK_cubes[IN_QUEUE]->get_spot(nxt_coord)) ) { // Mark the cluster voxel, see if it is new max, // and return true to indicate new spot needs to be recursed on MARK_cubes[IN_QUEUE]->set_spot_1( nxt_coord ); if ( current_max_bs_value < BS_cube->datac(nxt_coord) ) { current_max_bs_value = BS_cube->datac(nxt_coord); current_max_bs_coord = nxt_coord; } return true; } else { // Return false, indicating invalid spot return false; } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::generateClusterCube() { Vect3usi cur_coord; number_of_clusters = 0; progress_bar_ptr->SetRange(0, boundary_cube->wZ-1); progress_bar_ptr->SetPos(0); progress_bar_ptr->SetStep(1); progress_win_ptr->SetWindowText("Determining clusters..."); write_to_log("MA_VoxelCoding::generateClusterCube - Preparing for cluster cube generation."); // In case caching is used, split memory evenly between CL and SS SS_cube->resizeCacheBuffer( memory_limit_total_bytes/2 ); CL_cube->resizeCacheBuffer( memory_limit_total_bytes/2 ); // Clear Cluster Cube, and MARK cubes CL_cube->clear(); write_to_log("MA_VoxelCoding::generateClusterCube - Generating cluster cube."); // Find all clusters for ( cur_coord.z = 0; cur_coord.z < boundary_cube->wZ; cur_coord.z++) { for ( cur_coord.y = 0; cur_coord.y < boundary_cube->wY; cur_coord.y++) for ( cur_coord.x = 0; cur_coord.x < boundary_cube->wX; cur_coord.x++) { // Check if this is a new cluster if ( (!boundary_cube->get_spot(cur_coord)) && (CL_cube->datac(cur_coord) == 0) ) { // Increment number of clusters, and check for data overflow ++number_of_clusters; if ( CL_type_properties.getInfinity() == number_of_clusters ) { write_to_log("MA_VoxelCoding::generateClusterCube - FATAL ERROR - Data overflow for CL cube, %d.", number_of_clusters); doFullDump( MA_CRASH_ON_FATAL_ERROR ); } // Flood cluster with current ID current_mark_value = number_of_clusters; recurseOnAllNeighbors( cur_coord, &MA_VoxelCoding::markSingleClusterInCL ); } } progress_bar_ptr->StepIt(); } write_to_log("MA_VoxelCoding::generateClusterCube - Found %d clusters.", number_of_clusters); } // ---------------------------------------------------------------------------------------- // // Description: A work function called from RecurseOnAllNeighbors(), that will clear // all NOT_LM and IN_QUEUE spots belonging to current cluster. // // Starting State: -> Current Cluster is marked '1' in NOT_LM cube. // -> Any state for IN_QUEUE cube // // Ending State: -> Current Cluster is marked '0' in NOT_LM cube. // -> Current Cluster is marked '0' in IN_QUEUE cube. // ---------------------------------------------------------------------------------------- bool MA_VoxelCoding::markSingleClusterInCL( Vect3usi &cur_coord, Vect3usi &nxt_coord ) { if ( (SS_cube->datac(cur_coord) == SS_cube->datac(nxt_coord)) && (CL_cube->datac(nxt_coord) == 0) ) { // Mark the cluster voxel and return true to indicate new spot needs to be recursed on CL_cube->datac(nxt_coord, current_mark_value); return true; } else { // Return false, indicating invalid spot return false; } } // ---------------------------------------------------------------------------------------- // // Description - // ---------------------------------------------------------------------------------------- void MA_VoxelCoding::determineClustersVolumes() { Vect3usi cur_coord; current_volume_number = 0; for ( cur_coord.z = 0; cur_coord.z < boundary_cube->wZ; cur_coord.z++) { for ( cur_coord.y = 0; cur_coord.y < boundary_cube->wY; cur_coord.y++) for ( cur_coord.x = 0; cur_coord.x < boundary_cube->wX; cur_coord.x++) { if ( (!boundary_cube->get_spot(cur_coord)) && (!MARK_cubes[TRAVELED]->get_spot(cur_coord)) ) { recurseOnFaceNeighbors( cur_coord, &MA_VoxelCoding::determineClustersInVolume ); ++current_volume_number; } } } number_of_volumes = current_volume_number; } // ---------------------------------------------------------------------------------------- // // Description: A work function called from RecurseOnAllNeighbors(), that will clear // all NOT_LM and IN_QUEUE spots belonging to current cluster. // // Starting State: -> Current Cluster is marked '1' in NOT_LM cube. // -> Any state for IN_QUEUE cube // // Ending State: -> Current Cluster is marked '0' in NOT_LM cube. // -> Current Cluster is marked '0' in IN_QUEUE cube. // ---------------------------------------------------------------------------------------- bool MA_VoxelCoding::determineClustersInVolume( Vect3usi &, Vect3usi &nxt_coord ) { if ( (!boundary_cube->get_spot(nxt_coord)) && (!MARK_cubes[TRAVELED]->get_spot(nxt_coord)) ) { MARK_cubes[TRAVELED]->set_spot_1(nxt_coord); cluster_nodes_array[CL_cube->datac(nxt_coord)-1].volume_indx = current_volume_number; return true; } else { // Return false, indicating invalid spot return false; } }