void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList, int bReversed, char** papszOptions ) { TPSTransformInfo *psInfo; int iGCP; /* -------------------------------------------------------------------- */ /* Allocate transform info. */ /* -------------------------------------------------------------------- */ psInfo = (TPSTransformInfo *) CPLCalloc(sizeof(TPSTransformInfo),1); psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList ); psInfo->nGCPCount = nGCPCount; psInfo->bReversed = bReversed; psInfo->poForward = new VizGeorefSpline2D( 2 ); psInfo->poReverse = new VizGeorefSpline2D( 2 ); strcpy( psInfo->sTI.szSignature, "GTI" ); psInfo->sTI.pszClassName = "GDALTPSTransformer"; psInfo->sTI.pfnTransform = GDALTPSTransform; psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer; psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer; /* -------------------------------------------------------------------- */ /* Attach all the points to the transformation. */ /* -------------------------------------------------------------------- */ for( iGCP = 0; iGCP < nGCPCount; iGCP++ ) { double afPL[2], afXY[2]; afPL[0] = pasGCPList[iGCP].dfGCPPixel; afPL[1] = pasGCPList[iGCP].dfGCPLine; afXY[0] = pasGCPList[iGCP].dfGCPX; afXY[1] = pasGCPList[iGCP].dfGCPY; if( bReversed ) { psInfo->poReverse->add_point( afPL[0], afPL[1], afXY ); psInfo->poForward->add_point( afXY[0], afXY[1], afPL ); } else { psInfo->poForward->add_point( afPL[0], afPL[1], afXY ); psInfo->poReverse->add_point( afXY[0], afXY[1], afPL ); } } psInfo->nRefCount = 1; int nThreads = 1; if( nGCPCount > 100 ) { const char* pszWarpThreads = CSLFetchNameValue(papszOptions, "NUM_THREADS"); if (pszWarpThreads == NULL) pszWarpThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "1"); if (EQUAL(pszWarpThreads, "ALL_CPUS")) nThreads = CPLGetNumCPUs(); else nThreads = atoi(pszWarpThreads); } if( nThreads > 1 ) { /* Compute direct and reverse transforms in parallel */ void* hThread = CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo); psInfo->bReverseSolved = psInfo->poReverse->solve() != 0; if( hThread != NULL ) CPLJoinThread(hThread); else psInfo->bForwardSolved = psInfo->poForward->solve() != 0; } else { psInfo->bForwardSolved = psInfo->poForward->solve() != 0; psInfo->bReverseSolved = psInfo->poReverse->solve() != 0; } if( !psInfo->bForwardSolved || !psInfo->bReverseSolved ) { GDALDestroyTPSTransformer(psInfo); return NULL; } return psInfo; }
int main(int argc, char* argv[]) { int i; int nThreads = CPLGetNumCPUs(); std::vector<CPLJoinableThread*> apsThreads; Strategy eStrategy = STRATEGY_RANDOM; int bNewDatasetOption = FALSE; int nXSize = 5000; int nYSize = 5000; int nBands = 4; char** papszOptions = NULL; int bOnDisk = FALSE; std::vector<ThreadDescription> asThreadDescription; int bMemDriver = FALSE; GDALDataset* poMEMDS = NULL; int bMigrate = FALSE; int nMaxRequests = -1; argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); GDALAllRegister(); for(i = 1; i < argc; i++) { if( EQUAL(argv[i], "-threads") && i + 1 < argc) { i ++; nThreads = atoi(argv[i]); } else if( EQUAL(argv[i], "-loops") && i + 1 < argc) { i ++; nLoops = atoi(argv[i]); if( nLoops <= 0 ) nLoops = INT_MAX; } else if( EQUAL(argv[i], "-max_requests") && i + 1 < argc) { i ++; nMaxRequests = atoi(argv[i]); } else if( EQUAL(argv[i], "-strategy") && i + 1 < argc) { i ++; if( EQUAL(argv[i], "random") ) eStrategy = STRATEGY_RANDOM; else if( EQUAL(argv[i], "line") ) eStrategy = STRATEGY_LINE; else if( EQUAL(argv[i], "block") ) eStrategy = STRATEGY_BLOCK; else Usage(); } else if( EQUAL(argv[i], "-xsize") && i + 1 < argc) { i ++; nXSize = atoi(argv[i]); bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-ysize") && i + 1 < argc) { i ++; nYSize = atoi(argv[i]); bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-bands") && i + 1 < argc) { i ++; nBands = atoi(argv[i]); bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-co") && i + 1 < argc) { i ++; papszOptions = CSLAddString(papszOptions, argv[i]); bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-ondisk")) { bOnDisk = TRUE; bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-check")) { bCheck = TRUE; bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-memdriver")) { bMemDriver = TRUE; bNewDatasetOption = TRUE; } else if( EQUAL(argv[i], "-migrate")) bMigrate = TRUE; else if( argv[i][0] == '-' ) Usage(); else if( pszDataset == NULL ) pszDataset = argv[i]; else { Usage(); } } if( pszDataset != NULL && bNewDatasetOption ) Usage(); CPLDebug("TEST", "Using %d threads", nThreads); int bCreatedDataset = FALSE; if( pszDataset == NULL ) { bCreatedDataset = TRUE; if( bOnDisk ) pszDataset = "/tmp/tmp.tif"; else pszDataset = "/vsimem/tmp.tif"; GDALDataset* poDS = ((GDALDriver*)GDALGetDriverByName((bMemDriver) ? "MEM" : "GTiff"))->Create(pszDataset, nXSize, nYSize, nBands, GDT_Byte, papszOptions); if( bCheck ) { GByte* pabyLine = (GByte*) VSIMalloc(nBands * nXSize); for(int iY=0;iY<nYSize;iY++) { for(int iX=0;iX<nXSize;iX++) { for(int iBand=0;iBand<nBands;iBand++) { unsigned long seed = iBand * nXSize * nYSize + iY * nXSize + iX; pabyLine[iBand * nXSize + iX] = (GByte)(myrand_r(&seed) & 0xff); } } CPL_IGNORE_RET_VAL(poDS->RasterIO(GF_Write, 0, iY, nXSize, 1, pabyLine, nXSize, 1, GDT_Byte, nBands, NULL, 0, 0, 0 #ifdef GDAL_COMPILATION , NULL #endif )); } VSIFree(pabyLine); } if( bMemDriver ) poMEMDS = poDS; else GDALClose(poDS); } else { bCheck = FALSE; } CSLDestroy(papszOptions); papszOptions = NULL; Request* psGlobalRequestLast = NULL; for(i = 0; i < nThreads; i++ ) { GDALDataset* poDS; // Since GDAL 2.0, the MEM driver is thread-safe, i.e. does not use the block // cache, but only for operations not involving resampling, which is // the case here if( poMEMDS ) poDS = poMEMDS; else { poDS = (GDALDataset*)GDALOpen(pszDataset, GA_ReadOnly); if( poDS == NULL ) exit(1); } if( bMigrate ) { Resource* psResource = (Resource*)CPLMalloc(sizeof(Resource)); psResource->poDS = poDS; int nBufferSize; if( eStrategy == STRATEGY_RANDOM ) nBufferSize = CreateRandomStrategyRequests( poDS, nMaxRequests, psGlobalRequestList, psGlobalRequestLast); else if( eStrategy == STRATEGY_LINE ) nBufferSize = CreateLineStrategyRequests( poDS, nMaxRequests, psGlobalRequestList, psGlobalRequestLast); else nBufferSize = CreateBlockStrategyRequests( poDS, nMaxRequests, psGlobalRequestList, psGlobalRequestLast); psResource->pBuffer = CPLMalloc(nBufferSize); PutResourceAtEnd(psResource); } else { ThreadDescription sThreadDescription; sThreadDescription.poDS = poDS; sThreadDescription.psRequestList = NULL; Request* psRequestLast = NULL; if( eStrategy == STRATEGY_RANDOM ) sThreadDescription.nBufferSize = CreateRandomStrategyRequests( poDS, nMaxRequests, sThreadDescription.psRequestList, psRequestLast); else if( eStrategy == STRATEGY_LINE ) sThreadDescription.nBufferSize = CreateLineStrategyRequests( poDS, nMaxRequests, sThreadDescription.psRequestList, psRequestLast); else sThreadDescription.nBufferSize = CreateBlockStrategyRequests( poDS, nMaxRequests, sThreadDescription.psRequestList, psRequestLast); asThreadDescription.push_back(sThreadDescription); } } if( bCreatedDataset && poMEMDS == NULL && bOnDisk ) { CPLPushErrorHandler(CPLQuietErrorHandler); VSIUnlink(pszDataset); CPLPopErrorHandler(); } if( bMigrate ) { psLock = CPLCreateLock(LOCK_SPIN); } for(i = 0; i < nThreads; i++ ) { CPLJoinableThread* pThread; if( bMigrate ) pThread = CPLCreateJoinableThread(ThreadFuncWithMigration, NULL); else pThread = CPLCreateJoinableThread(ThreadFuncDedicatedDataset, &(asThreadDescription[i])); apsThreads.push_back(pThread); } for(i = 0; i < nThreads; i++ ) { CPLJoinThread(apsThreads[i]); if( !bMigrate && poMEMDS == NULL ) GDALClose(asThreadDescription[i].poDS); } while( psGlobalResourceList != NULL ) { CPLFree( psGlobalResourceList->pBuffer); if( poMEMDS == NULL ) GDALClose(psGlobalResourceList->poDS); Resource* psNext = psGlobalResourceList->psNext; CPLFree( psGlobalResourceList ); psGlobalResourceList = psNext; } if( psLock ) { CPLDestroyLock( psLock ); } if( bCreatedDataset && poMEMDS == NULL ) { CPLPushErrorHandler(CPLQuietErrorHandler); VSIUnlink(pszDataset); CPLPopErrorHandler(); } if( poMEMDS ) GDALClose(poMEMDS); assert( GDALGetCacheUsed64() == 0 ); GDALDestroyDriverManager(); CSLDestroy( argv ); return 0; }
void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList, int bReversed, char** papszOptions ) { TPSTransformInfo *psInfo; int iGCP; /* -------------------------------------------------------------------- */ /* Allocate transform info. */ /* -------------------------------------------------------------------- */ psInfo = (TPSTransformInfo *) CPLCalloc(sizeof(TPSTransformInfo),1); psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList ); psInfo->nGCPCount = nGCPCount; psInfo->bReversed = bReversed; psInfo->poForward = new VizGeorefSpline2D( 2 ); psInfo->poReverse = new VizGeorefSpline2D( 2 ); memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) ); psInfo->sTI.pszClassName = "GDALTPSTransformer"; psInfo->sTI.pfnTransform = GDALTPSTransform; psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer; psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer; psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarTPSTransformer; /* -------------------------------------------------------------------- */ /* Attach all the points to the transformation. */ /* -------------------------------------------------------------------- */ std::map< std::pair<double, double>, int > oMapPixelLineToIdx; std::map< std::pair<double, double>, int > oMapXYToIdx; for( iGCP = 0; iGCP < nGCPCount; iGCP++ ) { double afPL[2], afXY[2]; afPL[0] = pasGCPList[iGCP].dfGCPPixel; afPL[1] = pasGCPList[iGCP].dfGCPLine; afXY[0] = pasGCPList[iGCP].dfGCPX; afXY[1] = pasGCPList[iGCP].dfGCPY; std::map< std::pair<double, double>, int >::iterator oIter; oIter = oMapPixelLineToIdx.find( std::pair<double,double>(afPL[0], afPL[1]) ); if( oIter != oMapPixelLineToIdx.end() ) { if( afXY[0] == pasGCPList[oIter->second].dfGCPX && afXY[1] == pasGCPList[oIter->second].dfGCPY ) { continue; } else { CPLError(CE_Warning, CPLE_AppDefined, "GCP %d and %d have same (pixel,line)=(%f,%f) but different (X,Y): (%f,%f) vs (%f,%f)", iGCP + 1, oIter->second, afPL[0], afPL[1], afXY[0], afXY[1], pasGCPList[oIter->second].dfGCPX, pasGCPList[oIter->second].dfGCPY); } } else { oMapPixelLineToIdx[ std::pair<double,double>(afPL[0], afPL[1]) ] = iGCP; } oIter = oMapXYToIdx.find( std::pair<double,double>(afXY[0], afXY[1]) ); if( oIter != oMapXYToIdx.end() ) { CPLError(CE_Warning, CPLE_AppDefined, "GCP %d and %d have same (x,y)=(%f,%f) but different (pixel,line): (%f,%f) vs (%f,%f)", iGCP + 1, oIter->second, afXY[0], afXY[1], afPL[0], afPL[1], pasGCPList[oIter->second].dfGCPPixel, pasGCPList[oIter->second].dfGCPLine); } else { oMapXYToIdx[ std::pair<double,double>(afXY[0], afXY[1]) ] = iGCP; } bool bOK = true; if( bReversed ) { bOK &= psInfo->poReverse->add_point( afPL[0], afPL[1], afXY ); bOK &= psInfo->poForward->add_point( afXY[0], afXY[1], afPL ); } else { bOK &= psInfo->poForward->add_point( afPL[0], afPL[1], afXY ); bOK &= psInfo->poReverse->add_point( afXY[0], afXY[1], afPL ); } if( !bOK ) { GDALDestroyTPSTransformer(psInfo); return NULL; } } psInfo->nRefCount = 1; int nThreads = 1; if( nGCPCount > 100 ) { const char* pszWarpThreads = CSLFetchNameValue(papszOptions, "NUM_THREADS"); if (pszWarpThreads == NULL) pszWarpThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "1"); if (EQUAL(pszWarpThreads, "ALL_CPUS")) nThreads = CPLGetNumCPUs(); else nThreads = atoi(pszWarpThreads); } if( nThreads > 1 ) { /* Compute direct and reverse transforms in parallel */ CPLJoinableThread* hThread = CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo); psInfo->bReverseSolved = psInfo->poReverse->solve() != 0; if( hThread != NULL ) CPLJoinThread(hThread); else psInfo->bForwardSolved = psInfo->poForward->solve() != 0; } else { psInfo->bForwardSolved = psInfo->poForward->solve() != 0; psInfo->bReverseSolved = psInfo->poReverse->solve() != 0; } if( !psInfo->bForwardSolved || !psInfo->bReverseSolved ) { GDALDestroyTPSTransformer(psInfo); return NULL; } return psInfo; }