/*========================================================================= Program: Visualization Toolkit Module: TestIncrementalOctreePointLocator.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkMath.h" #include "vtkPoints.h" #include "vtkIdList.h" #include "vtkTestUtilities.h" #include "vtkUnstructuredGrid.h" #include "vtkUnstructuredGridReader.h" #include "vtkIncrementalOctreePointLocator.h" #define _BRUTE_FORCE_VERIFICATION_ // The following epsilon value is needed to address numerical inaccuracy / // precision issues on some platforms: Fast-Release-g++, Win32-cygwin344, // Win32-minGW, Win32-FreeVC++, and Win32-VS71. In particular, two of the // references of this value below, as marked, handle Win32-cygwin344 and // Win32-minGW. The numerical inaccuracy problem has nothing to do with // the incremental octree point locator or the associated incremental octree // node itself. Instead it is just due to the multiple sub-tests themselves // (combined in this single file) in which the brute-force mode employs many // if-statements / comparisons that involve double values. // // For example, vtkMath::Distance2BetweenPoints( point1, point2 ) may not be // directly used in if-statements (even for some platforms other than the above // mentioned 5), even though the incremental octree point locator always uses // double variables for computation and returning values. Another example is // that the min SQUARED distance D between point A (a given point) and point B // (the closest point to A) may not be directly used to test the number of points // within the SQUARED radius D relative to point A herein, though it is supposed // to be ok (and the number is expected to be 1). The fact is that an epsilon // needs to be added to D for such a test. Otherwise the numerical inaccuracy // issue would just cause 0 to be returned --- no any point exists within the // SQUARED radius D relative to A. Please note that this problem is not caused by // sqrt() at all because the incremental octree point locator offers an accurate // function variant FindPointsWithinSquaredRadius() to avoid the obvious numerical // inaccuracy related to sqrt(). // // Given the numerical inaccuracy issues on some platforms, the rapid verification // mode might not be used. Fortunately, this test is fast enough. #define INC_OCT_PNT_LOC_TESTS_ZERO 0.00000000000001 // --------------------------------------------------------------------------- // Meta information of the test data // // number of grid points = 2288 // number of unique points = 2200 (in terms of zero tolerance) // number of duplicate occurrences = 88 // bounding box: [ -2.839926, 2.862497 ] // [ -2.856848, 2.856848 ] // [ 0.000000, 1.125546 ] // // min squared distance = 1.036624e-005 (for zero-tolerance unique points) // max squared distance = 3.391319e+001 //---------------------------------------------------------------------------- // Swap an array of (or a single) int, double, or vtkIdType values when // loading little-endian / Win-based disk files on big-endian platforms. // Note the two data files for this test are in little-endian binary format. void SwapForBigEndian( unsigned char * theArray, int tupleSiz, int numTuple ) { int i, j; unsigned char * tmpChar0 = theArray; unsigned char * tmpChar1 = ( unsigned char * ) malloc( tupleSiz ); for ( j = 0; j < numTuple; j ++, tmpChar0 += tupleSiz ) { for ( i = 0; i < tupleSiz; i ++ ) { tmpChar1[i] = tmpChar0[ tupleSiz - 1 - i ]; } for ( i = 0; i < tupleSiz; i ++ ) { tmpChar0[i] = tmpChar1[i]; } } tmpChar0 = nullptr; free( tmpChar1 ); tmpChar1 = nullptr; } //---------------------------------------------------------------------------- int TestIncrementalOctreePointLocator( int argc, char * argv[] ) { // specifications int nClzNpts = 4; int octreRes[3] = { 64, 128, 256 }; double tolerans[2] = { 0.0, 0.01 }; // variables int r, t, m, i, j, k; int retValue = 0; int numbPnts = 0; int inserted = 0; int numInsrt = 0; int nLocPnts = 0; int nUniques = 0; int nDuplics = 0; int arrayIdx = 0; int numExPts = 0; char * fileName = nullptr; FILE * diskFile = nullptr; FILE * pntsFile = nullptr; double pntCoord[3] = { 0.0, 0.0, 0.0 }; double tmpDist2 = 0.0; double fTempRad = 0.0; double * pDataPts = nullptr; double * xtentPts = nullptr; double * pLocPnts = nullptr; double * minDist2 = nullptr; double * maxDist2 = nullptr; double * clzNdst2 = nullptr; vtkPoints * dataPnts = nullptr; vtkPoints * insrtPts = nullptr; vtkIdType pointIdx; vtkIdType * truthIds = nullptr; vtkIdType * resltIds = nullptr; vtkIdList * ptIdList = nullptr; vtkIdList * idxLists[3] = { nullptr, nullptr, nullptr }; vtkUnstructuredGrid * unstruct = nullptr; vtkUnstructuredGridReader * ugReader = nullptr; vtkIncrementalOctreePointLocator * octLocat = nullptr; size_t n; // load an unstructured grid dataset fileName = vtkTestUtilities::ExpandDataFileName ( argc, argv, "Data/post.vtk" ); ugReader = vtkUnstructuredGridReader::New(); ugReader->SetFileName( fileName ); delete [] fileName; ugReader->Update(); unstruct = ugReader->GetOutput(); dataPnts = unstruct->GetPoints(); numbPnts = dataPnts->GetNumberOfPoints(); // open a file for reading or writing the ground truth data fileName = vtkTestUtilities::ExpandDataFileName ( argc, argv, "Data/IncOctPntLocResult.dat" ); #ifndef _BRUTE_FORCE_VERIFICATION_ diskFile = fopen( fileName, "rb" ); truthIds = ( vtkIdType * ) realloc( truthIds, sizeof( vtkIdType ) * numbPnts ); #endif delete [] fileName; fileName = nullptr; // obtain the 3D point coordinates pDataPts = ( double * ) realloc( pDataPts, sizeof( double ) * 3 * numbPnts ); for ( i = 0; i < numbPnts; i ++ ) { dataPnts->GetPoint( i, pDataPts + ( i << 1 ) + i ); } // allocate memory for exactly duplicate points and inherit some points nUniques = 4; nDuplics = 300; arrayIdx = numbPnts * 3; numExPts = numbPnts + nUniques * nDuplics; xtentPts = ( double * ) realloc( xtentPts, sizeof( double ) * 3 * numExPts ); memcpy( xtentPts, pDataPts, sizeof( double ) * 3 * numbPnts ); // add an additional number of exactly duplicate points for ( j = 0; j < nUniques; j ++ ) { i = ( numbPnts / ( nUniques + 2 ) ) * ( j + 1 ); i = ( i << 1 ) + i; pntCoord[0] = pDataPts[ i ]; pntCoord[1] = pDataPts[ i + 1 ]; pntCoord[2] = pDataPts[ i + 2 ]; for ( i = 0; i < nDuplics; i ++, arrayIdx += 3 ) { xtentPts[ arrayIdx ] = pntCoord[0]; xtentPts[ arrayIdx + 1 ] = pntCoord[1]; xtentPts[ arrayIdx + 2 ] = pntCoord[2]; } } // memory allocation ptIdList = vtkIdList::New(); ptIdList->Allocate( numbPnts, numbPnts >> 1 ); insrtPts = vtkPoints::New(); insrtPts->Allocate( numbPnts, numbPnts >> 1 ); octLocat = vtkIncrementalOctreePointLocator::New(); // ========================================================================= // ============================ Point Insertion ============================ // ========================================================================= for ( r = 0; ( r < 3 ) && ( retValue == 0 ); r ++ ) // three resolutions { // ----------------------------------------------------------------------- // --------------------- check-based point insertion --------------------- // ----------------------------------------------------------------------- for ( t = 0; ( t < 2 ) && ( retValue == 0 ); t ++ ) // two tolerances for ( m = 0; ( m < 3 ) && ( retValue == 0 ); m ++ ) // three functions { ptIdList->Reset(); // indices of the inserted points: based on dataPnts insrtPts->Reset(); octLocat->FreeSearchStructure(); octLocat->SetMaxPointsPerLeaf( octreRes[r] ); octLocat->SetTolerance( tolerans[t] ); octLocat->InitPointInsertion ( insrtPts, dataPnts->GetBounds(), numbPnts ); // --------------------------------------------------------------------- if ( m == 0 ) // vtkIncrementalOctreePointLocator::InsertUniquePoint() { for ( i = 0; i < numbPnts; i ++ ) { inserted = octLocat->InsertUniquePoint ( pDataPts + ( i << 1 ) + i, pointIdx ); if ( inserted ) ptIdList->InsertNextId( i ); } } else if ( m == 1 ) // vtkIncrementalOctreePointLocator::InsertNextPoint() { for ( i = 0; i < numbPnts; i ++ ) { inserted = octLocat->IsInsertedPoint( pDataPts + ( i << 1 ) + i ); if ( inserted == -1 ) { octLocat->InsertNextPoint( pDataPts + ( i << 1 ) + i ); ptIdList->InsertNextId( i ); } } } else // vtkIncrementalOctreePointLocator::InsertPoint() { numInsrt = 0; for ( i = 0; i < numbPnts; i ++ ) { inserted = octLocat->IsInsertedPoint( pDataPts + ( i << 1 ) + i ); if ( inserted == -1 ) { octLocat->InsertPoint( numInsrt ++, pDataPts + ( i << 1 ) + i ); ptIdList->InsertNextId( i ); } } } // -------------------------------------------------------------------// #ifdef _BRUTE_FORCE_VERIFICATION_ // --------------------------------------------------------------------- // verify the point insertion result in brute force mode double tempPnt0[3]; double tempPnt1[3]; double tolerns2[2] = { tolerans[0] * tolerans[0], tolerans[1] * tolerans[1] }; numInsrt = ptIdList->GetNumberOfIds(); // check if the squared distance between any two inserted points is // less than the threshold for ( j = 0; ( j < numInsrt - 1 ) && ( retValue == 0 ); j ++ ) { insrtPts->GetPoint( j, tempPnt0 ); for ( i = j + 1; ( i < numInsrt ) && ( retValue == 0 ); i ++ ) { insrtPts->GetPoint( i, tempPnt1 ); tmpDist2 = vtkMath::Distance2BetweenPoints( tempPnt0, tempPnt1 ); if ( tmpDist2 <= tolerns2[t]) retValue = 1; } } // check if there is any point whose distance to ALL inserted points // is greater than the threshold for ( j = 0; ( j < numbPnts ) && ( retValue == 0 ); j ++ ) { if ( ptIdList->IsId( j ) != -1 ) continue; // already inserted int bGreater = 1; for ( i = 0; i < numInsrt; i ++ ) { insrtPts->GetPoint( i, tempPnt1 ); tmpDist2 = vtkMath::Distance2BetweenPoints ( pDataPts + ( j << 1 ) + j, tempPnt1 ); if ( tmpDist2 <= tolerns2[t] ) bGreater = 0; // No 'break' here !!! } retValue = bGreater; } // -------------------------------------------------------------------// #else // --------------------------------------------------------------------- // rapid point index-based verification n = fread( &numInsrt, sizeof( int ), 1, diskFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &numInsrt ), sizeof( int ), 1 ); #endif if ( numInsrt == ptIdList->GetNumberOfIds() ) { int samePtId = 1; n = fread( truthIds, sizeof( vtkIdType ), numInsrt, diskFile ); if (n != static_cast(numInsrt)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) truthIds, sizeof( vtkIdType ), numInsrt ); #endif for ( i = 0; ( i < numInsrt ) && ( samePtId == 1 ); i ++ ) { samePtId = ( truthIds[i] == ptIdList->GetId( i ) ) ? 1 : 0; } retValue = 1 - samePtId; } else retValue = 1; // -------------------------------------------------------------------// #endif } // end of two tolerances and three functions // ----------------------------------------------------------------------- // ------------------ direct check-free point insertion ------------------ // ----------------------------------------------------------------------- insrtPts->Reset(); octLocat->FreeSearchStructure(); octLocat->SetMaxPointsPerLeaf( octreRes[r] ); octLocat->InitPointInsertion ( insrtPts, dataPnts->GetBounds(), numbPnts ); for ( i = 0; i < numbPnts; i ++ ) { octLocat->InsertPointWithoutChecking ( pDataPts + ( i << 1 ) + i, pointIdx, 1 ); } retValue = ( insrtPts->GetNumberOfPoints() == numbPnts ) ? 0 : 1; } // end of three resolutions // ========================================================================= // direct check-free insertion of a huge number of EXACTLY DUPLICATE points // (number > the maximum number of points per leaf node) // ========================================================================= if ( retValue == 0 ) { // perform direct / check-free point insertion for ( r = 0; ( r < 3 ) && ( retValue == 0 ); r ++ ) // three resolutions { insrtPts->Reset(); octLocat->FreeSearchStructure(); octLocat->SetMaxPointsPerLeaf( octreRes[r] ); octLocat->InitPointInsertion ( insrtPts, dataPnts->GetBounds(), numExPts ); for ( i = 0; i < numExPts; i ++ ) { octLocat->InsertPointWithoutChecking ( xtentPts + ( i << 1 ) + i, pointIdx, 1 ); } retValue = ( insrtPts->GetNumberOfPoints() == numExPts ) ? 0 : 1; } } if ( xtentPts ) { free( xtentPts ); xtentPts = nullptr; } // =======================================================================// // =======================================================================// // reclaim this vtkPoints as it will be never used again if ( insrtPts ) { insrtPts->Delete(); insrtPts = nullptr; } // ========================================================================= // ============================ Point Location ============================ // ========================================================================= // load points and radius data from a disk file for point location tasks fileName = vtkTestUtilities::ExpandDataFileName ( argc, argv, "Data/IncOctPntLocData.dat" ); pntsFile = fopen( fileName, "rb" ); delete [] fileName; fileName = nullptr; n = fread( &nLocPnts, sizeof( int ), 1, pntsFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; fclose(pntsFile); free(pDataPts); return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &nLocPnts ), sizeof( int ), 1 ); #endif pLocPnts = ( double * ) malloc( sizeof( double ) * nLocPnts * 3 ); minDist2 = ( double * ) malloc( sizeof( double ) * nLocPnts ); maxDist2 = ( double * ) malloc( sizeof( double ) * nLocPnts ); n = fread( pLocPnts, sizeof( double ), nLocPnts * 3, pntsFile ); if (n != static_cast(nLocPnts * 3)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; fclose(pntsFile); free(pLocPnts); free(minDist2); free(maxDist2); free(pDataPts); return 1; } //fread( minDist2, sizeof( double ), nLocPnts, pntsFile ); //fread( maxDist2, sizeof( double ), nLocPnts, pntsFile ); #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) pLocPnts, sizeof( double ), nLocPnts * 3 ); //SwapForBigEndian // ( ( unsigned char * ) minDist2, sizeof( double ), nLocPnts ); //SwapForBigEndian // ( ( unsigned char * ) maxDist2, sizeof( double ), nLocPnts ); #endif fclose( pntsFile ); pntsFile = nullptr; // destroy the context of point insertion while attaching the dataset octLocat->FreeSearchStructure(); octLocat->SetDataSet( unstruct ); // memory allocation clzNdst2 = ( double * ) realloc( clzNdst2, sizeof( double ) * nClzNpts ); for ( i = 0; i < 3; i ++ ) { idxLists[i] = vtkIdList::New(); idxLists[i]->Allocate( nClzNpts, nClzNpts ); } // the main component for ( r = 0; ( r < 3 ) && ( retValue == 0 ); r ++ ) // three resolutions { // establish a new octree with the specified resolution octLocat->Modified(); octLocat->SetMaxPointsPerLeaf( octreRes[r] ); octLocat->BuildLocator(); // memory allocation resltIds = ( vtkIdType * ) realloc( resltIds, sizeof( vtkIdType ) * nLocPnts ); #ifndef _BRUTE_FORCE_VERIFICATION_ truthIds = ( vtkIdType * ) realloc( truthIds, sizeof( vtkIdType ) * nLocPnts ); #endif // ----------------------------------------------------------------------- // -------------------- location of the closest point -------------------- // ----------------------------------------------------------------------- // find the closest point for ( i = 0; i < nLocPnts; i ++ ) { resltIds[i] = octLocat->FindClosestPoint( pLocPnts + ( i << 1 ) + i, minDist2 + i ); } #ifdef _BRUTE_FORCE_VERIFICATION_ // ----------------------------------------------------------------------- // verify the result in brute force mode for ( j = 0; ( j < nLocPnts ) && ( retValue == 0 ); j ++ ) for ( i = 0; ( i < numbPnts ) && ( retValue == 0 ); i ++ ) { if ( i == resltIds[j] ) continue; // just the selected closest point tmpDist2 = vtkMath::Distance2BetweenPoints ( pLocPnts + ( j << 1 ) + j, pDataPts + ( i << 1 ) + i ); if ( tmpDist2 + INC_OCT_PNT_LOC_TESTS_ZERO < minDist2[j] ) retValue = 1; } // ---------------------------------------------------------------------// #else // ----------------------------------------------------------------------- // rapid point index-based verification n = fread( &nLocPnts, sizeof( int ), 1, diskFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &nLocPnts ), sizeof( int ), 1 ); #endif n = fread( truthIds, sizeof( vtkIdType ), nLocPnts, diskFile ); if (n != static_cast(nLocPnts)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) truthIds, sizeof( vtkIdType ), nLocPnts ); #endif for ( i = 0; ( i < nLocPnts ) && ( retValue == 0 ); i ++ ) { retValue = ( resltIds[i] == truthIds[i] ) ? 0 : 1; } // ---------------------------------------------------------------------// #endif if ( retValue == 1 ) continue; // ----------------------------------------------------------------------- // ------------------ location of the closest N points ------------------- // ----------------------------------------------------------------------- // memory allocation ptIdList->SetNumberOfIds( nClzNpts * 10 ); // to claim part of the memory resltIds = ( vtkIdType * ) realloc( resltIds, sizeof( vtkIdType ) * nClzNpts * nLocPnts ); #ifndef _BRUTE_FORCE_VERIFICATION_ truthIds = ( vtkIdType * ) realloc( truthIds, sizeof( vtkIdType ) * nClzNpts * nLocPnts ); n = fread( &numInsrt, sizeof( int ), 1, diskFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &numInsrt ), sizeof( int ), 1 ); #endif n = fread( truthIds, sizeof( vtkIdType ), numInsrt, diskFile ); if (n != static_cast(numInsrt)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) truthIds, sizeof( vtkIdType ), numInsrt ); #endif #endif // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- // find the closest N points (with embedded brute-force verification) for ( i = 0; i < nLocPnts; i ++ ) { ptIdList->Reset(); octLocat->FindClosestNPoints ( nClzNpts, pLocPnts + ( i << 1 ) + i, ptIdList ); // --------------------------------------------------------------------- // verify the result in brute force mode #ifdef _BRUTE_FORCE_VERIFICATION_ // check the order of the closest points for ( j = 0; j < nClzNpts; j ++ ) { pointIdx = ptIdList->GetId( j ); clzNdst2[j] = vtkMath::Distance2BetweenPoints ( pLocPnts + ( i << 1 ) + i, pDataPts + ( pointIdx << 1 ) + pointIdx ); } for ( j = 0; ( j < nClzNpts - 1 ) && ( retValue == 0 ); j ++ ) { retValue = ( clzNdst2[j + 1] >= clzNdst2[j] ) ? 0 : 1; } // write some data for locating the closest point // within a radius and the points within a radius minDist2[i] = clzNdst2[0]; maxDist2[i] = clzNdst2[ nClzNpts - 1 ]; // check if there are any ignored but closer points for ( j = 0; ( j < numbPnts ) && ( retValue == 0 ); j ++ ) { tmpDist2 = vtkMath::Distance2BetweenPoints ( pLocPnts + ( i << 1 ) + i, pDataPts + ( j << 1 ) + j ); if ( tmpDist2 + INC_OCT_PNT_LOC_TESTS_ZERO // for cygwin and minGW < clzNdst2[ nClzNpts - 1 ] // Not "<=" here as there && ptIdList->IsId( j ) == -1 // may be other points that were ) retValue = 1; // rejected simply due to the limit of N } if ( retValue == 1 ) break; #endif // -------------------------------------------------------------------// // transfer the point indices for subsequent file writing purposes memcpy( resltIds + i * nClzNpts, ptIdList->GetPointer( 0 ), sizeof( vtkIdType ) * nClzNpts ); } // ---------------------------------------------------------------------// // ---------------------------------------------------------------------// // ----------------------------------------------------------------------- // rapid point index-based verification #ifndef _BRUTE_FORCE_VERIFICATION_ numInsrt = nClzNpts * nLocPnts; // data has been read at the beginning for ( i = 0; ( i < numInsrt ) && ( retValue == 0 ); i ++ ) { retValue = ( resltIds[i] == truthIds[i] ) ? 0 : 1; } #endif // ---------------------------------------------------------------------// if ( retValue == 1 ) continue; // ----------------------------------------------------------------------- // ------------ location of the closest point within a radius ------------ // ----------------------------------------------------------------------- // memory allocation resltIds = ( vtkIdType * ) realloc( resltIds, sizeof( vtkIdType ) * nLocPnts * 3 ); // find the closest point within three radii for ( i = 0; i < nLocPnts; i ++ ) { j = ( i << 1 ) + i; pointIdx = octLocat->FindClosestPoint( pLocPnts + j, minDist2 + i ); // there are some points falling on the in-octree points fTempRad = ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) ? 0.000001 : minDist2[i]; fTempRad = sqrt( fTempRad ); // causes inaccuracy if minDist2 is nonzero resltIds[ j ] = octLocat->FindClosestPointWithinRadius ( fTempRad * 0.5, pLocPnts + j, tmpDist2 ); if ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) resltIds[ j + 1 ] = octLocat->FindClosestPointWithinRadius ( fTempRad * 1.0, pLocPnts + j, tmpDist2 ); else // for non-zero cases, use the original squared radius for accuracy resltIds[ j + 1 ] = octLocat->FindClosestPointWithinSquaredRadius ( minDist2[i], pLocPnts + j, tmpDist2 ); resltIds[ j + 2 ] = octLocat->FindClosestPointWithinRadius ( fTempRad * 1.5, pLocPnts + j, tmpDist2 ); // ----------------------------------------------------------------------- // verify the result in brute force mode #ifdef _BRUTE_FORCE_VERIFICATION_ if ( ( ( minDist2[i] > INC_OCT_PNT_LOC_TESTS_ZERO ) && ( resltIds[j] != -1 ) ) || ( ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) && ( resltIds[j] != pointIdx ) ) || ( resltIds[ j + 1 ] != pointIdx ) || ( resltIds[ j + 2 ] != pointIdx ) ) { retValue = 1; break; } // ---------------------------------------------------------------------// #endif } // ----------------------------------------------------------------------- // rapid point index-based verification #ifndef _BRUTE_FORCE_VERIFICATION_ n = fread( &numInsrt, sizeof( int ), 1, diskFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &numInsrt ), sizeof( int ), 1 ); #endif truthIds = ( vtkIdType * ) realloc( truthIds, sizeof( vtkIdType ) * numInsrt ); n = fread( truthIds, sizeof( vtkIdType ), numInsrt, diskFile ); if (n != static_cast(numInsrt)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) truthIds, sizeof( vtkIdType ), numInsrt ); #endif for ( i = 0; ( i < numInsrt ) && ( retValue == 0 ); i ++ ) { retValue = ( resltIds[i] == truthIds[i] ) ? 0 : 1; } #endif // ---------------------------------------------------------------------// if ( retValue == 1 ) continue; // ----------------------------------------------------------------------- // --------------- location of the points within a radius ---------------- // ----------------------------------------------------------------------- ptIdList->Reset(); for ( i = 0; i < nLocPnts; i ++ ) { // set the coordinate index of the point under check j = ( i << 1 ) + i; minDist2[i] += INC_OCT_PNT_LOC_TESTS_ZERO; // for cygwin and minGW // obtain the points within three radii (use squared radii for test // as sqrt can incur inaccuracy that complicates the test) idxLists[0]->Reset(); idxLists[1]->Reset(); idxLists[2]->Reset(); if ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) { // each ( maxDist2[i] * 0.3 ) has been guaranteed to be > // INC_OCT_PNT_LOC_TESTS_ZERO octLocat->FindPointsWithinSquaredRadius ( maxDist2[i] * 0.3, pLocPnts + j, idxLists[0] ); octLocat->FindPointsWithinSquaredRadius ( maxDist2[i] * 0.6, pLocPnts + j, idxLists[1] ); octLocat->FindPointsWithinSquaredRadius ( maxDist2[i], pLocPnts + j, idxLists[2] ); } else { octLocat->FindPointsWithinSquaredRadius ( minDist2[i] * 0.5, pLocPnts + j, idxLists[0] ); octLocat->FindPointsWithinSquaredRadius ( minDist2[i], pLocPnts + j, idxLists[1] ); octLocat->FindPointsWithinSquaredRadius ( maxDist2[i], pLocPnts + j, idxLists[2] ); if ( idxLists[0]->GetNumberOfIds() == 0 ) idxLists[0]->InsertNextId( -1 ); // to handle an empty id list } // copy the point indices to a vtkIdList for comparison and file writing for ( m = 0; m < 3; m ++ ) { numInsrt = idxLists[m]->GetNumberOfIds(); for ( k = 0; k < numInsrt; k ++ ) { ptIdList->InsertNextId( idxLists[m]->GetId( k ) ); } } // --------------------------------------------------------------------- // verify the result in brute force mode #ifdef _BRUTE_FORCE_VERIFICATION_ // check if the monotonical property holds among the 3 point-index lists if ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) { pointIdx = octLocat->FindClosestPoint( pLocPnts + j ); if ( idxLists[0]->IsId( pointIdx ) == -1 || idxLists[1]->IsId( pointIdx ) == -1 || idxLists[2]->IsId( pointIdx ) == -1 || idxLists[1]->GetNumberOfIds() < idxLists[0]->GetNumberOfIds() || idxLists[2]->GetNumberOfIds() < idxLists[0]->GetNumberOfIds() || idxLists[2]->GetNumberOfIds() < idxLists[1]->GetNumberOfIds() ) retValue = 1; } else { if ( idxLists[0]->GetNumberOfIds() != 1 || idxLists[0]->GetId( 0 ) != -1 || idxLists[1]->GetNumberOfIds() < 1 || idxLists[2]->GetNumberOfIds() < idxLists[1]->GetNumberOfIds() ) retValue = 1; } // check the points within each of the three radii for ( m = 0; ( m < 3 ) && ( retValue == 0 ); m ++ ) { // get the squared radius actually used if ( minDist2[i] <= INC_OCT_PNT_LOC_TESTS_ZERO ) { if ( m == 0 ) fTempRad = maxDist2[i] * 0.3; else if ( m == 1 ) fTempRad = maxDist2[i] * 0.6; else fTempRad = maxDist2[i]; } else { if ( m == 0 ) fTempRad = minDist2[i] * 0.5; else if ( m == 1 ) fTempRad = minDist2[i]; else fTempRad = maxDist2[i]; } // check if there is any false insertion numInsrt = idxLists[m]->GetNumberOfIds(); for ( k = 0; ( k < numInsrt ) && ( retValue == 0 ); k ++ ) { if ( m == 0 && idxLists[0]->GetId( 0 ) == -1 ) break; pointIdx = idxLists[m]->GetId( k ); pointIdx = ( pointIdx << 1 ) + pointIdx; tmpDist2 = vtkMath::Distance2BetweenPoints ( pLocPnts + j, pDataPts + pointIdx ); if ( tmpDist2 > fTempRad + INC_OCT_PNT_LOC_TESTS_ZERO ) retValue = 1; } // check if there is any missed insertion numInsrt = 0; for ( k = 0; k < numbPnts; k ++ ) { tmpDist2 = vtkMath::Distance2BetweenPoints ( pLocPnts + j, pDataPts + ( k << 1 ) + k ); if ( tmpDist2 + INC_OCT_PNT_LOC_TESTS_ZERO <= fTempRad ) numInsrt ++; } // get the actual size of the vtkIdList for comparison int listSize = ( m == 0 && idxLists[0]->GetId( 0 ) == -1 ) ? 0 // for an actually nullptr vtkIdList : idxLists[m]->GetNumberOfIds(); if ( numInsrt > listSize ) retValue = 1; } #endif // -------------------------------------------------------------------// } // ----------------------------------------------------------------------- // rapid point index-based verification #ifndef _BRUTE_FORCE_VERIFICATION_ n = fread( &numInsrt, sizeof( int ), 1, diskFile ); if (n != 1) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) ( &numInsrt ), sizeof( int ), 1 ); #endif truthIds = ( vtkIdType * ) realloc( truthIds, sizeof( vtkIdType ) * numInsrt ); n = fread( truthIds, sizeof( vtkIdType ), numInsrt, diskFile ); if (n != static_cast(numInsrt)) { cerr << "IO error " << __FILE__ << ":" << __LINE__ << "\n"; return 1; } #ifdef VTK_WORDS_BIGENDIAN SwapForBigEndian ( ( unsigned char * ) truthIds, sizeof( vtkIdType ), numInsrt ); #endif vtkIdType * tmpPtIds = ptIdList->GetPointer( 0 ); for ( i = 0; ( i < numInsrt ) && ( retValue == 0 ); i ++ ) { retValue = ( tmpPtIds[i] == truthIds[i] ) ? 0 : 1; } tmpPtIds = nullptr; #endif // ---------------------------------------------------------------------// } // memory clearance dataPnts = nullptr; unstruct = nullptr; if ( ptIdList ) { ptIdList->Delete(); ptIdList = nullptr; } if ( octLocat ) { octLocat->Delete(); octLocat = nullptr; } if ( ugReader ) { ugReader->Delete(); ugReader = nullptr; } free( truthIds ); truthIds = nullptr; free( resltIds ); resltIds = nullptr; free( pDataPts ); pDataPts = nullptr; free( pLocPnts ); pLocPnts = nullptr; free( minDist2 ); minDist2 = nullptr; free( maxDist2 ); maxDist2 = nullptr; free( clzNdst2 ); clzNdst2 = nullptr; if ( diskFile ) { fclose( diskFile ); diskFile = nullptr; } for ( i = 0; i < 3; i ++ ) { if ( idxLists[i] ) { idxLists[i]->Delete(); idxLists[i] = nullptr; } } return retValue; }