def runProcess(processIndex, tasksQueue, resultsQueue, minX, minY, maxX, maxY, outputFolder, tempFolder, axisTiles): kill_received = False while not kill_received: inputFile = None try: # This call will patiently wait until new job is available inputFile = tasksQueue.get() except: # if there is an error we will quit kill_received = True if inputFile == None: # If we receive a None job, it means we can stop kill_received = True else: # Get number of points and BBOX of this file (fCount, fMinX, fMinY, _, fMaxX, fMaxY, _, _, _, _, _, _, _) = utils.getPCFileDetails(inputFile) print ('Processing', os.path.basename(inputFile), fCount, fMinX, fMinY, fMaxX, fMaxY) # For the four vertices of the BBOX we get in which tile they should go posMinXMinY = getTileIndex(fMinX, fMinY, minX, minY, maxX, maxY, axisTiles) posMinXMaxY = getTileIndex(fMinX, fMaxY, minX, minY, maxX, maxY, axisTiles) posMaxXMinY = getTileIndex(fMaxX, fMinY, minX, minY, maxX, maxY, axisTiles) posMaxXMaxY = getTileIndex(fMaxX, fMaxY, minX, minY, maxX, maxY, axisTiles) if (posMinXMinY == posMinXMaxY) and (posMinXMinY == posMaxXMinY) and (posMinXMinY == posMaxXMaxY): # If they are the same the whole file can be directly copied to the tile tileFolder = outputFolder + '/' + getTileName(*posMinXMinY) if not os.path.isdir(tileFolder): utils.shellExecute('mkdir -p ' + tileFolder) utils.shellExecute('cp ' + inputFile + ' ' + tileFolder) else: # If not, we run PDAL gridder to split the file in pieces that can go to the tiles tGCount = runPDALSplitter(processIndex, inputFile, outputFolder, tempFolder, minX, minY, maxX, maxY, axisTiles) if tGCount != fCount: print ('WARNING: split version of ', inputFile, ' does not have same number of points (', tGCount, 'expected', fCount, ')') resultsQueue.put((processIndex, inputFile, fCount))
def runPDALSplitter(processIndex, inputFile, outputFolder, tempFolder, minX, minY, maxX, maxY, axisTiles): pTempFolder = tempFolder + '/' + str(processIndex) if not os.path.isdir(pTempFolder): utils.shellExecute('mkdir -p ' + pTempFolder) # Get the lenght required by the PDAL split filter in order to get "squared" tiles lengthPDAL = (maxX - minX) / float(axisTiles) utils.shellExecute('pdal split -i ' + inputFile + ' -o ' + pTempFolder + '/' + os.path.basename(inputFile) + ' --origin_x ' + str(minX) + ' --origin_y ' + str(minY) + ' --length ' + str(lengthPDAL)) tGCount = 0 for gFile in os.listdir(pTempFolder): (gCount, gFileMinX, gFileMinY, _, gFileMaxX, gFileMaxY, _, _, _, _, _, _, _) = utils.getPCFileDetails(pTempFolder + '/' + gFile) # This tile should match with some tile. Let's use the central point to see which one pX = gFileMinX + ((gFileMaxX - gFileMinX) / 2.) pY = gFileMinY + ((gFileMaxY - gFileMinY) / 2.) tileFolder = outputFolder + '/' + getTileName( *getTileIndex(pX, pY, minX, minY, maxX, maxY, axisTiles)) if not os.path.isdir(tileFolder): utils.shellExecute('mkdir -p ' + tileFolder) utils.shellExecute('mv ' + pTempFolder + '/' + gFile + ' ' + tileFolder + '/' + gFile) tGCount += gCount return tGCount
def runProcess(processIndex, tasksQueue, resultsQueue, minX, minY, maxX, maxY, outputFolder, tempFolder, axisTiles): kill_received = False while not kill_received: inputFile = None try: # This call will patiently wait until new job is available inputFile = tasksQueue.get() except: # if there is an error we will quit kill_received = True if inputFile == None: # If we receive a None job, it means we can stop kill_received = True else: # Get number of points and BBOX of this file (fCount, fMinX, fMinY, _, fMaxX, fMaxY, _, _, _, _, _, _, _) = utils.getPCFileDetails(inputFile) print('Processing', os.path.basename(inputFile), fCount, fMinX, fMinY, fMaxX, fMaxY) # For the four vertices of the BBOX we get in which tile they should go posMinXMinY = getTileIndex(fMinX, fMinY, minX, minY, maxX, maxY, axisTiles) posMinXMaxY = getTileIndex(fMinX, fMaxY, minX, minY, maxX, maxY, axisTiles) posMaxXMinY = getTileIndex(fMaxX, fMinY, minX, minY, maxX, maxY, axisTiles) posMaxXMaxY = getTileIndex(fMaxX, fMaxY, minX, minY, maxX, maxY, axisTiles) if (posMinXMinY == posMinXMaxY) and (posMinXMinY == posMaxXMinY) and (posMinXMinY == posMaxXMaxY): # If they are the same the whole file can be directly copied to the tile tileFolder = outputFolder + '/' + getTileName(*posMinXMinY) if not os.path.isdir(tileFolder): utils.shellExecute('mkdir -p ' + tileFolder) utils.shellExecute('cp ' + inputFile + ' ' + tileFolder) else: # If not, we run PDAL gridder to split the file in pieces that can go to the tiles tGCount = runPDALSplitter(processIndex, inputFile, outputFolder, tempFolder, minX, minY, maxX, maxY, axisTiles) if tGCount != fCount: print('WARNING: split version of ', inputFile, ' does not have same number of points (', tGCount, 'expected', fCount, ')') resultsQueue.put((processIndex, inputFile, fCount))
def run(inputFolder, outputFolder, runMode, useLink, numberProcs): # Check input parameters if not os.path.isdir(inputFolder): raise Exception('Error: Input folder does not exist!') if os.path.isfile(outputFolder): raise Exception('Error: There is a file with the same name as the output folder. Please, delete it!') elif os.path.isdir(outputFolder) and os.listdir(outputFolder): raise Exception('Error: Output folder exists and it is not empty. Please, delete the data in the output folder!') if runMode not in ('s','i','si','is'): raise Exception('Error: running mode must be s, i, or si') # Make it absolute path inputFolder = os.path.abspath(inputFolder) utils.shellExecute('mkdir -p ' + outputFolder) # Create queues for the distributed processing tasksQueue = multiprocessing.Queue() # The queue of tasks (inputFiles) resultsQueue = multiprocessing.Queue() # The queue of results tilesNames = os.listdir(inputFolder) if 'tiles.js' in tilesNames: tilesNames.remove('tiles.js') utils.shellExecute('cp ' + inputFolder + '/tiles.js ' + outputFolder+ '/tiles.js') numTiles = len(tilesNames) # Add tasks/inputFiles for i in range(numTiles): tasksQueue.put(inputFolder + '/' + tilesNames[i]) for i in range(numberProcs): #we add as many None jobs as numberProcs to tell them to terminate (queue is FIFO) tasksQueue.put(None) processes = [] # We start numberProcs users processes for i in range(numberProcs): processes.append(multiprocessing.Process(target=runProcess, args=(i, tasksQueue, resultsQueue, outputFolder, runMode, useLink))) processes[-1].start() # Get all the results (actually we do not need the returned values) for i in range(numTiles): resultsQueue.get() print ('Completed %d of %d (%.02f%%)' % (i+1, numTiles, 100. * float(i+1) / float(numTiles))) # wait for all users to finish their execution for i in range(numberProcs): processes[i].join()
def runProcess(processIndex, tasksQueue, resultsQueue, outputFolder, runMode, useLink): kill_received = False while not kill_received: tileAbsPath = None try: # This call will patiently wait until new job is available tileAbsPath = tasksQueue.get() except: # if there is an error we will quit kill_received = True if tileAbsPath == None: # If we receive a None job, it means we can stop kill_received = True else: tileOutputFolder = outputFolder + '/' + os.path.basename(tileAbsPath) tileFilesAbsPaths = utils.getFiles(tileAbsPath, recursive = True) for i,tileFileAbsPath in enumerate(tileFilesAbsPaths): if (len(tileFilesAbsPaths) == 1) and os.path.isfile(tileAbsPath): outputAbsPath = tileOutputFolder else: if i == 0: os.system('mkdir -p ' + tileOutputFolder) outputAbsPath = outputFolder + '/' + os.path.basename(tileAbsPath) + '/' + os.path.basename(tileFileAbsPath) commands = [] if 's' in runMode: cmd = os.environ["LASSORT"] commands.append(cmd + ' -i ' + tileFileAbsPath + ' -o ' + outputAbsPath) else: if useLink: commands.append('ln -s ' + tileFileAbsPath + ' ' + outputAbsPath) else: commands.append('cp ' + tileFileAbsPath + ' ' + outputAbsPath) if 'i' in runMode: commands.append('lasindex -i ' + outputAbsPath) for command in commands: utils.shellExecute(command, True) resultsQueue.put((processIndex, tileAbsPath))
def run(inputFolderA, inputFolderB, outputFolder, moveFiles): # Check input parameters if (not os.path.isdir(inputFolderA)) or (not os.path.isdir(inputFolderB)): raise Exception('Error: Some of the input folder does not exist!') if os.path.isfile(outputFolder): raise Exception('Error: There is a file with the same name as the output folder. Please, delete it!') elif os.path.isdir(outputFolder) and os.listdir(outputFolder): raise Exception('Error: Output folder exists and it is not empty. Please, delete the data in the output folder!') # Make the paths absolute path inputFolderA = os.path.abspath(inputFolderA) inputFolderB = os.path.abspath(inputFolderB) outputFolder = os.path.abspath(outputFolder) if moveFiles: cmcommand = 'mv ' else: cmcommand = 'cp -r ' dataA = inputFolderA + '/data' dataB = inputFolderB + '/data' dataO = outputFolder + '/data' # Check if the octtrees have actual data (i.e. one folder with the root node) hasNodeA = os.listdir(dataA) == ['r',] hasNodeB = os.listdir(dataB) == ['r',] if hasNodeA or hasNodeB: utils.shellExecute('mkdir -p ' + outputFolder) if hasNodeA and hasNodeB: # If both Octrees have data we need to merge them # Create output cloud.js from joining the two input ones cloudJSA = inputFolderA + '/cloud.js' cloudJSB = inputFolderB + '/cloud.js' if not (os.path.isfile(cloudJSA)) or not (os.path.isfile(cloudJSB)): raise Exception('Error: Some cloud.js is missing!') # We also get the hierarchyStepSize hierarchyStepSize = createCloudJS(cloudJSA, cloudJSB, outputFolder + '/cloud.js') listFileRootA = os.listdir(dataA + '/r') if 'r.las' in listFileRootA: extension = 'las' elif 'r.laz' in listFileRootA: extension = 'laz' else: raise Exception('Error: ' + __file__ + ' only compatible with las/laz format') joinNode('r', dataA + '/r', dataB + '/r', dataO + '/r', hierarchyStepSize, extension, cmcommand) elif hasA: utils.shellExecute(cmcommand + inputFolderA + '/* ' + outputFolder) else: utils.shellExecute(cmcommand + inputFolderB + '/* ' + outputFolder) else: print ('Nothing to merge: both Octtrees are empty!')
def runPDALSplitter(processIndex, inputFile, outputFolder, tempFolder, minX, minY, maxX, maxY, axisTiles): pTempFolder = tempFolder + '/' + str(processIndex) if not os.path.isdir(pTempFolder): utils.shellExecute('mkdir -p ' + pTempFolder) # Get the lenght required by the PDAL split filter in order to get "squared" tiles lengthPDAL = (maxX - minX) / float(axisTiles) utils.shellExecute('pdal split -i ' + inputFile + ' -o ' + pTempFolder + '/' + os.path.basename(inputFile) + ' --origin_x=' + str(minX) + ' --origin_y=' + str(minY) + ' --length ' + str(lengthPDAL)) tGCount = 0 for gFile in os.listdir(pTempFolder): (gCount, gFileMinX, gFileMinY, _, gFileMaxX, gFileMaxY, _, _, _, _, _, _, _) = utils.getPCFileDetails(pTempFolder + '/' + gFile) # This tile should match with some tile. Let's use the central point to see which one pX = gFileMinX + ((gFileMaxX - gFileMinX) / 2.) pY = gFileMinY + ((gFileMaxY - gFileMinY) / 2.) tileFolder = outputFolder + '/' + getTileName(*getTileIndex(pX, pY, minX, minY, maxX, maxY, axisTiles)) if not os.path.isdir(tileFolder): utils.shellExecute('mkdir -p ' + tileFolder) utils.shellExecute('mv ' + pTempFolder + '/' + gFile + ' ' + tileFolder + '/' + gFile) tGCount += gCount return tGCount
def main(): args = argument_parser().parse_args() print ('Input folder: ', args.input) print ('Output folder: ', args.output) print ('Mode: ', args.mode) print ('Use Link: ', args.link) print ('Number of processes: ', args.proc) # Check the LAStools lassort.exe is installed if ('s' in args.mode): cmd = os.environ.get("LASSORT",None) if(not cmd or utils.shellExecute(cmd + ' -version').count('LAStools') == 0): raise Exception("LAStools lassort.exe is not found!. Please define LASSORT environment variable!") try: t0 = time.time() print ('Starting ' + os.path.basename(__file__) + '...') run(args.input, args.output, args.mode, args.link, args.proc) print ('Finished in %.2f seconds' % (time.time() - t0)) except: print ('Execution failed!') print (traceback.format_exc())
def run(inputFolder, outputFolder, tempFolder, extent, numberTiles, numberProcs): # Check input parameters if not os.path.isdir(inputFolder) and not os.path.isfile(inputFolder): raise Exception('Error: Input folder does not exist!') if os.path.isfile(outputFolder): raise Exception( 'Error: There is a file with the same name as the output folder. Please, delete it!' ) elif os.path.isdir(outputFolder) and os.listdir(outputFolder): raise Exception( 'Error: Output folder exists and it is not empty. Please, delete the data in the output folder!' ) # Get the number of tiles per dimension (x and y) axisTiles = math.sqrt(numberTiles) if (not axisTiles.is_integer()) or (int(axisTiles) % 2): raise Exception( 'Error: Number of tiles must be the square of number which is power of 2!' ) axisTiles = int(axisTiles) # Create output and temporal folder utils.shellExecute('mkdir -p ' + outputFolder) utils.shellExecute('mkdir -p ' + tempFolder) (minX, minY, maxX, maxY) = extent.split(' ') minX = float(minX) minY = float(minY) maxX = float(maxX) maxY = float(maxY) if (maxX - minX) != (maxY - minY): raise Exception( 'Error: Tiling requires that maxX-minX must be equal to maxY-minY!' ) inputFiles = utils.getFiles(inputFolder, recursive=True) numInputFiles = len(inputFiles) print('%s contains %d files' % (inputFolder, numInputFiles)) # Create queues for the distributed processing tasksQueue = multiprocessing.Queue() # The queue of tasks (inputFiles) resultsQueue = multiprocessing.Queue() # The queue of results # Add tasks/inputFiles for i in range(numInputFiles): tasksQueue.put(inputFiles[i]) for i in range( numberProcs ): #we add as many None jobs as numberProcs to tell them to terminate (queue is FIFO) tasksQueue.put(None) processes = [] # We start numberProcs users processes for i in range(numberProcs): processes.append( multiprocessing.Process(target=runProcess, args=(i, tasksQueue, resultsQueue, minX, minY, maxX, maxY, outputFolder, tempFolder, axisTiles))) processes[-1].start() # Get all the results (actually we do not need the returned values) numPoints = 0 for i in range(numInputFiles): (processIndex, inputFile, inputFileNumPoints) = resultsQueue.get() numPoints += inputFileNumPoints print( 'Completed %d of %d (%.02f%%)' % (i + 1, numInputFiles, 100. * float(i + 1) / float(numInputFiles))) # wait for all users to finish their execution for i in range(numberProcs): processes[i].join() # Write the tile.js file with information about the tiles cFile = open(outputFolder + '/tiles.js', 'w') d = {} d["NumberPoints"] = numPoints d["numXTiles"] = axisTiles d["numYTiles"] = axisTiles d["boundingBox"] = {'lx': minX, 'ly': minY, 'ux': maxX, 'uy': maxY} cFile.write(json.dumps(d, indent=4, sort_keys=True)) cFile.close()
def fixHeader(inputFile, outputFile): (_, minX, minY, minZ, maxX, maxY, maxZ, _, _, _, _, _, _) = utils.getPCFileDetails(inputFile) utils.shellExecute('lasinfo -i %s -nc -nv -nco -set_bounding_box %f %f %f %f %f %f' % (outputFile, minX, minY, minZ, maxX, maxY, maxZ))
def joinNode(node, nodeAbsPathA, nodeAbsPathB, nodeAbsPathO, hierarchyStepSize, extension, cmcommand): hrcFile = node + '.hrc' hrcA = None if os.path.isfile(nodeAbsPathA + '/' + hrcFile): # Check if there is data in this node in Octtree A (we check if the HRC file for this node exist) hrcA = utils.readHRC(nodeAbsPathA + '/' + hrcFile, hierarchyStepSize) if len(os.listdir(nodeAbsPathA)) == 2: hrcA[0][0] = utils.getPCFileDetails(nodeAbsPathA + '/' + node + extension)[0] hrcB = None if os.path.isfile(nodeAbsPathB + '/' + hrcFile): # Check if there is data in this node in Octtree B (we check if the HRC file for this node exist) hrcB = utils.readHRC(nodeAbsPathB + '/' + hrcFile, hierarchyStepSize) if len(os.listdir(nodeAbsPathB)) == 2: hrcB[0][0] = utils.getPCFileDetails(nodeAbsPathB + '/' + node + extension)[0] if hrcA != None and hrcB != None: utils.shellExecute('mkdir -p ' + nodeAbsPathO) # If both Octtrees A and B have data in this node we have to merge them hrcO = utils.initHRC(hierarchyStepSize) for level in range(hierarchyStepSize+2): numChildrenA = len(hrcA[level]) numChildrenB = len(hrcB[level]) numChildrenO = max((numChildrenA, numChildrenB)) if level < (hierarchyStepSize+1): for i in range(numChildrenO): hasNodeA = (i < numChildrenA) and (hrcA[level][i] > 0) hasNodeB = (i < numChildrenB) and (hrcB[level][i] > 0) (childNode, isFile) = utils.getNodeName(level, i, node, hierarchyStepSize, extension) if hasNodeA and hasNodeB: hrcO[level].append(hrcA[level][i] + hrcB[level][i]) #merge lAZ or folder (iteratively) if isFile: utils.shellExecute('lasmerge -i ' + nodeAbsPathA + '/' + childNode + ' ' + nodeAbsPathB + '/' + childNode + ' -o ' + nodeAbsPathO + '/' + childNode) #We now need to set the header of the output file as the input files (lasmerge will have shrink it and we do not want that fixHeader(nodeAbsPathA + '/' + childNode, nodeAbsPathO + '/' + childNode) else: joinNode(node + childNode, nodeAbsPathA + '/' + childNode, nodeAbsPathB + '/' + childNode, nodeAbsPathO + '/' + childNode, hierarchyStepSize, extension, cmcommand) elif hasNodeA: #mv / cp hrcO[level].append(hrcA[level][i]) utils.shellExecute(cmcommand + nodeAbsPathA + '/' + childNode + ' ' + nodeAbsPathO + '/' + childNode) elif hasNodeB: #mv / cp hrcO[level].append(hrcB[level][i]) utils.shellExecute(cmcommand + nodeAbsPathB + '/' + childNode + ' ' + nodeAbsPathO + '/' + childNode) else: hrcO[level].append(0) else: hrcO[level] = list(numpy.array(hrcA[level] + ([0]*(numChildrenO - numChildrenA))) + numpy.array(hrcB[level] + ([0]*(numChildrenO - numChildrenB)))) # Write the HRC file utils.writeHRC(nodeAbsPathO + '/' + hrcFile, hierarchyStepSize, hrcO) elif hrcA != None: # Only Octtree A has data in this node. We can directly copy it to the output Octtree utils.shellExecute(cmcommand + nodeAbsPathA + ' ' + nodeAbsPathO) elif hrcB != None: # Only Octtree B has data in this node. We can directly copy it to the output Octtree utils.shellExecute(cmcommand + nodeAbsPathB + ' ' + nodeAbsPathO)
def fixHeader(inputFile, outputFile): (_, minX, minY, minZ, maxX, maxY, maxZ, _, _, _, _, _, _) = utils.getPCFileDetails(inputFile) utils.shellExecute( 'lasinfo -i %s -nc -nv -nco -set_bounding_box %f %f %f %f %f %f' % (outputFile, minX, minY, minZ, maxX, maxY, maxZ))
def joinNode(node, nodeAbsPathA, nodeAbsPathB, nodeAbsPathO, hierarchyStepSize, extension, cmcommand): hrcFile = node + '.hrc' hrcA = None if os.path.isfile(nodeAbsPathA + '/' + hrcFile): # Check if there is data in this node in Octtree A (we check if the HRC file for this node exist) hrcA = utils.readHRC(nodeAbsPathA + '/' + hrcFile, hierarchyStepSize) if len(os.listdir(nodeAbsPathA)) == 2: hrcA[0][0] = utils.getPCFileDetails(nodeAbsPathA + '/' + node + extension)[0] hrcB = None if os.path.isfile(nodeAbsPathB + '/' + hrcFile): # Check if there is data in this node in Octtree B (we check if the HRC file for this node exist) hrcB = utils.readHRC(nodeAbsPathB + '/' + hrcFile, hierarchyStepSize) if len(os.listdir(nodeAbsPathB)) == 2: hrcB[0][0] = utils.getPCFileDetails(nodeAbsPathB + '/' + node + extension)[0] if hrcA != None and hrcB != None: utils.shellExecute('mkdir -p ' + nodeAbsPathO) # If both Octtrees A and B have data in this node we have to merge them hrcO = utils.initHRC(hierarchyStepSize) for level in range(hierarchyStepSize + 2): numChildrenA = len(hrcA[level]) numChildrenB = len(hrcB[level]) numChildrenO = max((numChildrenA, numChildrenB)) if level < (hierarchyStepSize + 1): for i in range(numChildrenO): hasNodeA = (i < numChildrenA) and (hrcA[level][i] > 0) hasNodeB = (i < numChildrenB) and (hrcB[level][i] > 0) (childNode, isFile) = utils.getNodeName(level, i, node, hierarchyStepSize, extension) if hasNodeA and hasNodeB: hrcO[level].append(hrcA[level][i] + hrcB[level][i]) #merge lAZ or folder (iteratively) if isFile: utils.shellExecute('lasmerge -i ' + nodeAbsPathA + '/' + childNode + ' ' + nodeAbsPathB + '/' + childNode + ' -o ' + nodeAbsPathO + '/' + childNode) #We now need to set the header of the output file as the input files (lasmerge will have shrink it and we do not want that fixHeader(nodeAbsPathA + '/' + childNode, nodeAbsPathO + '/' + childNode) else: joinNode(node + childNode, nodeAbsPathA + '/' + childNode, nodeAbsPathB + '/' + childNode, nodeAbsPathO + '/' + childNode, hierarchyStepSize, extension, cmcommand) elif hasNodeA: #mv / cp hrcO[level].append(hrcA[level][i]) utils.shellExecute(cmcommand + nodeAbsPathA + '/' + childNode + ' ' + nodeAbsPathO + '/' + childNode) elif hasNodeB: #mv / cp hrcO[level].append(hrcB[level][i]) utils.shellExecute(cmcommand + nodeAbsPathB + '/' + childNode + ' ' + nodeAbsPathO + '/' + childNode) else: hrcO[level].append(0) else: hrcO[level] = list( numpy.array(hrcA[level] + ([0] * (numChildrenO - numChildrenA))) + numpy.array(hrcB[level] + ([0] * (numChildrenO - numChildrenB)))) # Write the HRC file utils.writeHRC(nodeAbsPathO + '/' + hrcFile, hierarchyStepSize, hrcO) elif hrcA != None: # Only Octtree A has data in this node. We can directly copy it to the output Octtree utils.shellExecute(cmcommand + nodeAbsPathA + ' ' + nodeAbsPathO) elif hrcB != None: # Only Octtree B has data in this node. We can directly copy it to the output Octtree utils.shellExecute(cmcommand + nodeAbsPathB + ' ' + nodeAbsPathO)
def run(inputFolderA, inputFolderB, outputFolder, moveFiles): # Check input parameters if (not os.path.isdir(inputFolderA)) or (not os.path.isdir(inputFolderB)): raise Exception('Error: Some of the input folder does not exist!') if os.path.isfile(outputFolder): raise Exception( 'Error: There is a file with the same name as the output folder. Please, delete it!' ) elif os.path.isdir(outputFolder) and os.listdir(outputFolder): raise Exception( 'Error: Output folder exists and it is not empty. Please, delete the data in the output folder!' ) # Make the paths absolute path inputFolderA = os.path.abspath(inputFolderA) inputFolderB = os.path.abspath(inputFolderB) outputFolder = os.path.abspath(outputFolder) if moveFiles: cmcommand = 'mv ' else: cmcommand = 'cp -r ' dataA = inputFolderA + '/data' dataB = inputFolderB + '/data' dataO = outputFolder + '/data' # Check if the octtrees have actual data (i.e. one folder with the root node) hasNodeA = os.listdir(dataA) == [ 'r', ] hasNodeB = os.listdir(dataB) == [ 'r', ] if hasNodeA or hasNodeB: utils.shellExecute('mkdir -p ' + outputFolder) if hasNodeA and hasNodeB: # If both Octrees have data we need to merge them # Create output cloud.js from joining the two input ones cloudJSA = inputFolderA + '/cloud.js' cloudJSB = inputFolderB + '/cloud.js' if not (os.path.isfile(cloudJSA)) or not ( os.path.isfile(cloudJSB)): raise Exception('Error: Some cloud.js is missing!') # We also get the hierarchyStepSize hierarchyStepSize = createCloudJS(cloudJSA, cloudJSB, outputFolder + '/cloud.js') listFileRootA = os.listdir(dataA + '/r') if 'r.las' in listFileRootA: extension = 'las' elif 'r.laz' in listFileRootA: extension = 'laz' else: raise Exception('Error: ' + __file__ + ' only compatible with las/laz format') joinNode('r', dataA + '/r', dataB + '/r', dataO + '/r', hierarchyStepSize, extension, cmcommand) elif hasA: utils.shellExecute(cmcommand + inputFolderA + '/* ' + outputFolder) else: utils.shellExecute(cmcommand + inputFolderB + '/* ' + outputFolder) else: print('Nothing to merge: both Octtrees are empty!')
def run(inputFolder, outputFolder, tempFolder, extent, numberTiles, numberProcs): # Check input parameters if not os.path.isdir(inputFolder) and not os.path.isfile(inputFolder): raise Exception('Error: Input folder does not exist!') if os.path.isfile(outputFolder): raise Exception('Error: There is a file with the same name as the output folder. Please, delete it!') elif os.path.isdir(outputFolder) and os.listdir(outputFolder): raise Exception('Error: Output folder exists and it is not empty. Please, delete the data in the output folder!') # Get the number of tiles per dimension (x and y) axisTiles = math.sqrt(numberTiles) if (not axisTiles.is_integer()) or (int(axisTiles) % 2): raise Exception('Error: Number of tiles must be the square of number which is power of 2!') axisTiles = int(axisTiles) # Create output and temporal folder utils.shellExecute('mkdir -p ' + outputFolder) utils.shellExecute('mkdir -p ' + tempFolder) (minX, minY, maxX, maxY) = extent.split(' ') minX = float(minX) minY = float(minY) maxX = float(maxX) maxY = float(maxY) if (maxX - minX) != (maxY - minY): raise Exception('Error: Tiling requires that maxX-minX must be equal to maxY-minY!') inputFiles = utils.getFiles(inputFolder, recursive=True) numInputFiles = len(inputFiles) print ('%s contains %d files' % (inputFolder, numInputFiles)) # Create queues for the distributed processing tasksQueue = multiprocessing.Queue() # The queue of tasks (inputFiles) resultsQueue = multiprocessing.Queue() # The queue of results # Add tasks/inputFiles for i in range(numInputFiles): tasksQueue.put(inputFiles[i]) for i in range(numberProcs): #we add as many None jobs as numberProcs to tell them to terminate (queue is FIFO) tasksQueue.put(None) processes = [] # We start numberProcs users processes for i in range(numberProcs): processes.append(multiprocessing.Process(target=runProcess, args=(i, tasksQueue, resultsQueue, minX, minY, maxX, maxY, outputFolder, tempFolder, axisTiles))) processes[-1].start() # Get all the results (actually we do not need the returned values) numPoints = 0 for i in range(numInputFiles): (processIndex, inputFile, inputFileNumPoints) = resultsQueue.get() numPoints += inputFileNumPoints print ('Completed %d of %d (%.02f%%)' % (i+1, numInputFiles, 100. * float(i+1) / float(numInputFiles))) # wait for all users to finish their execution for i in range(numberProcs): processes[i].join() # Write the tile.js file with information about the tiles cFile = open(outputFolder + '/tiles.js', 'w') d = {} d["NumberPoints"] = numPoints d["numXTiles"] = axisTiles d["numYTiles"] = axisTiles d["boundingBox"] = {'lx':minX,'ly':minY,'ux':maxX,'uy':maxY} cFile.write(json.dumps(d,indent=4,sort_keys=True)) cFile.close()