bool ccVolumeCalcTool::updateGrid() { if (!m_cloud2) { assert(false); return false; } //per-cell Z computation ProjectionType projectionType = getTypeOfProjection(); //vertical dimension const unsigned char Z = getProjectionDimension(); assert(Z >= 0 && Z <= 2); const unsigned char X = Z == 2 ? 0 : Z +1; const unsigned char Y = X == 2 ? 0 : X +1; //cloud bounding-box --> grid size ccBBox box = getCustomBBox(); if (!box.isValid()) { return false; } double gridStep = getGridStep(); assert(gridStep != 0); CCVector3d boxDiag( static_cast<double>(box.maxCorner().x) - static_cast<double>(box.minCorner().x), static_cast<double>(box.maxCorner().y) - static_cast<double>(box.minCorner().y), static_cast<double>(box.maxCorner().z) - static_cast<double>(box.minCorner().z) ); if (boxDiag.u[X] <= 0 || boxDiag.u[Y] <= 0) { ccLog::Error("Invalid cloud bounding box!"); return false; } unsigned gridWidth = static_cast<unsigned>(ceil(boxDiag.u[X] / gridStep)); unsigned gridHeight = static_cast<unsigned>(ceil(boxDiag.u[Y] / gridStep)); //grid size unsigned gridTotalSize = gridWidth * gridHeight; if (gridTotalSize == 1) { if (QMessageBox::question(0,"Unexpected grid size","The generated grid will only have 1 cell! Do you want to proceed anyway?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::No) return false; } else if (gridTotalSize > 10000000) { if (QMessageBox::question(0,"Big grid size","The generated grid will have more than 10.000.000 cells! Do you want to proceed anyway?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::No) return false; } //memory allocation if (!m_grid.init(gridWidth,gridHeight)) { //not enough memory ccLog::Error("Not enough memory"); return false; } m_grid.gridStep = gridStep; m_grid.minCorner = CCVector3d::fromArray(box.minCorner().u); //ground ccGenericPointCloud* groundCloud = 0; double groundHeight = 0; switch (groundComboBox->currentIndex()) { case 0: groundHeight = groundEmptyValueDoubleSpinBox->value(); break; case 1: groundCloud = m_cloud1 ? m_cloud1 : m_cloud2; break; case 2: groundCloud = m_cloud2; break; default: assert(false); return false; } ccProgressDialog pDlg(true,this); RasterGrid groundRaster; if (groundCloud) { if (!groundRaster.init(gridWidth,gridHeight)) { //not enough memory ccLog::Error("Not enough memory"); return false; } groundRaster.gridStep = m_grid.gridStep; groundRaster.minCorner = m_grid.minCorner; if (groundRaster.fillWith( groundCloud, Z, projectionType, getFillEmptyCellsStrategy(fillGroundEmptyCellsComboBox) == INTERPOLATE, INVALID_PROJECTION_TYPE, &pDlg)) { groundRaster.fillEmptyGridCells(getFillEmptyCellsStrategy(fillGroundEmptyCellsComboBox), groundEmptyValueDoubleSpinBox->value()); ccLog::Print(QString("[Volume] Ground raster grid: size: %1 x %2 / heights: [%3 ; %4]").arg(m_grid.width).arg(m_grid.height).arg(m_grid.minHeight).arg(m_grid.maxHeight)); } else { return false; } } //ceil ccGenericPointCloud* ceilCloud = 0; double ceilHeight = 0; switch (ceilComboBox->currentIndex()) { case 0: ceilHeight = ceilEmptyValueDoubleSpinBox->value(); break; case 1: ceilCloud = m_cloud1 ? m_cloud1 : m_cloud2; break; case 2: ceilCloud = m_cloud2; break; default: assert(false); return false; } RasterGrid ceilRaster; if (ceilCloud) { if (!ceilRaster.init(gridWidth,gridHeight)) { //not enough memory ccLog::Error("Not enough memory"); return false; } ceilRaster.gridStep = m_grid.gridStep; ceilRaster.minCorner = m_grid.minCorner; if (ceilRaster.fillWith(ceilCloud, Z, projectionType, getFillEmptyCellsStrategy(fillCeilEmptyCellsComboBox) == INTERPOLATE, INVALID_PROJECTION_TYPE, &pDlg)) { ceilRaster.fillEmptyGridCells(getFillEmptyCellsStrategy(fillCeilEmptyCellsComboBox), ceilEmptyValueDoubleSpinBox->value()); ccLog::Print(QString("[Volume] Ceil raster grid: size: %1 x %2 / heights: [%3 ; %4]").arg(m_grid.width).arg(m_grid.height).arg(m_grid.minHeight).arg(m_grid.maxHeight)); } else { return false; } } //update grid and compute volume { pDlg.setMethodTitle("Volume computation"); pDlg.setInfo(qPrintable(QString("Cells: %1 x %2").arg(m_grid.width).arg(m_grid.height))); pDlg.start(); pDlg.show(); QApplication::processEvents(); CCLib::NormalizedProgress nProgress(&pDlg, m_grid.width*m_grid.height); ReportInfo repotInfo; size_t ceilNonMatchingCount = 0; size_t groundNonMatchingCount = 0; size_t cellCount = 0; //at least one of the grid is based on a cloud m_grid.nonEmptyCellCount = 0; for (unsigned i=0; i<m_grid.height; ++i) { for (unsigned j=0; j<m_grid.width; ++j) { RasterCell& cell = m_grid.data[i][j]; bool validGround = true; cell.minHeight = groundHeight; if (groundCloud) { cell.minHeight = groundRaster.data[i][j].h; validGround = (cell.minHeight == cell.minHeight); } bool validCeil = true; cell.maxHeight = ceilHeight; if (ceilCloud) { cell.maxHeight = ceilRaster.data[i][j].h; validCeil = (cell.maxHeight == cell.maxHeight); } if (validGround && validCeil) { cell.h = cell.maxHeight - cell.minHeight; cell.nbPoints = 1; repotInfo.volume += cell.h; repotInfo.surface += 1.0; ++m_grid.nonEmptyCellCount; //= matching count ++cellCount; } else { if (validGround) { ++cellCount; ++groundNonMatchingCount; } else if (validCeil) { ++cellCount; ++ceilNonMatchingCount; } cell.h = std::numeric_limits<double>::quiet_NaN(); cell.nbPoints = 0; } cell.avgHeight = (groundHeight + ceilHeight)/2; cell.stdDevHeight = 0; if (!nProgress.oneStep()) { ccLog::Warning("[Volume] Process cancelled by the user"); return false; } } } m_grid.validCellCount = m_grid.nonEmptyCellCount; //count the average number of valid neighbors { size_t validNeighborsCount = 0; size_t count = 0; for (unsigned i=1; i<m_grid.height-1; ++i) { for (unsigned j=1; j<m_grid.width-1; ++j) { RasterCell& cell = m_grid.data[i][j]; if (cell.h == cell.h) { for (unsigned k=i-1; k<=i+1; ++k) { for (unsigned l=j-1; l<=j+1; ++l) { if (k != i || l != j) { RasterCell& otherCell = m_grid.data[k][l]; if (otherCell.h == otherCell.h) { ++validNeighborsCount; } } } } ++count; } } } if (count) { repotInfo.averageNeighborsPerCell = static_cast<double>(validNeighborsCount) / count; } } repotInfo.matchingPrecent = static_cast<float>(m_grid.validCellCount * 100) / cellCount; repotInfo.groundNonMatchingPercent = static_cast<float>(groundNonMatchingCount * 100) / cellCount; repotInfo.ceilNonMatchingPercent = static_cast<float>(ceilNonMatchingCount * 100) / cellCount; float cellArea = static_cast<float>(m_grid.gridStep * m_grid.gridStep); repotInfo.volume *= cellArea; repotInfo.surface *= cellArea; outputReport(repotInfo); } m_grid.setValid(true); return true; }
bool ccRasterizeTool::updateGrid(bool interpolateSF/*=false*/) { if (!m_cloud) { assert(false); return false; } //main parameters ProjectionType projectionType = getTypeOfProjection(); ProjectionType sfInterpolation = interpolateSF ? getTypeOfSFInterpolation() : INVALID_PROJECTION_TYPE; //vertical dimension const unsigned char Z = getProjectionDimension(); assert(Z >= 0 && Z <= 2); const unsigned char X = Z == 2 ? 0 : Z +1; const unsigned char Y = X == 2 ? 0 : X +1; //cloud bounding-box --> grid size ccBBox box = getCustomBBox(); if (!box.isValid()) return false; double gridStep = getGridStep(); assert(gridStep != 0); CCVector3d boxDiag( static_cast<double>(box.maxCorner().x) - static_cast<double>(box.minCorner().x), static_cast<double>(box.maxCorner().y) - static_cast<double>(box.minCorner().y), static_cast<double>(box.maxCorner().z) - static_cast<double>(box.minCorner().z) ); if (boxDiag.u[X] <= 0 || boxDiag.u[Y] <= 0) { ccLog::Error("Invalid cloud bounding box!"); return false; } unsigned gridWidth = static_cast<unsigned>(ceil(boxDiag.u[X] / gridStep)); unsigned gridHeight = static_cast<unsigned>(ceil(boxDiag.u[Y] / gridStep)); //grid size unsigned gridTotalSize = gridWidth * gridHeight; if (gridTotalSize == 1) { if (QMessageBox::question(0,"Unexpected grid size","The generated grid will only have 1 cell! Do you want to proceed anyway?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::No) return false; } else if (gridTotalSize > 10000000) { if (QMessageBox::question(0,"Big grid size","The generated grid will have more than 10.000.000 cells! Do you want to proceed anyway?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::No) return false; } removeContourLines(); //memory allocation if (!m_grid.init(gridWidth,gridHeight)) { //not enough memory ccLog::Error("Not enough memory"); return false; } m_grid.gridStep = gridStep; m_grid.minCorner = CCVector3d::fromArray(box.minCorner().u); ccProgressDialog pDlg(true,this); if (m_grid.fillWith(m_cloud, Z, projectionType, getFillEmptyCellsStrategy(fillEmptyCellsComboBox) == INTERPOLATE, sfInterpolation, &pDlg)) { ccLog::Print(QString("[Rasterize] Current raster grid: size: %1 x %2 / heights: [%3 ; %4]").arg(m_grid.width).arg(m_grid.height).arg(m_grid.minHeight).arg(m_grid.maxHeight)); } return true; }