ccPointCloud* cc2Point5DimEditor::convertGridToCloud( const std::vector<ExportableFields>& exportedFields, bool interpolateSF, bool resampleInputCloud, ccGenericPointCloud* inputCloud, bool fillEmptyCells, double emptyCellsHeight) const { if (!m_grid.isValid()) return 0; unsigned pointsCount = (fillEmptyCells ? m_grid.width * m_grid.height : m_grid.validCellCount); if (pointsCount == 0) { ccLog::Warning("[Rasterize] Empty grid!"); return 0; } ccPointCloud* cloudGrid = 0; if (resampleInputCloud) { CCLib::ReferenceCloud refCloud(inputCloud); if (refCloud.reserve(m_grid.nonEmptyCellCount)) { for (unsigned j=0; j<m_grid.height; ++j) { for (unsigned i=0; i<m_grid.width; ++i) { const RasterCell& cell = m_grid.data[j][i]; if (cell.nbPoints) //non empty cell { refCloud.addPointIndex(cell.pointIndex); } } } assert(refCloud.size() != 0); cloudGrid = inputCloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(inputCloud)->partialClone(&refCloud) : ccPointCloud::From(&refCloud,inputCloud); cloudGrid->setPointSize(0); //to avoid display issues //even if we have already resampled the original cloud we may have to create new points and/or scalar fields //if (!interpolateSF && !fillEmptyCells) // return cloudGrid; } else { ccLog::Warning("[Rasterize] Not enough memory!"); return 0; } } else { cloudGrid = new ccPointCloud("grid"); } assert(cloudGrid); //shall we generate per-cell fields as well? std::vector<CCLib::ScalarField*> exportedSFs; if (!exportedFields.empty()) { exportedSFs.resize(exportedFields.size(),0); for (size_t i=0; i<exportedFields.size(); ++i) { int sfIndex = -1; switch (exportedFields[i]) { case PER_CELL_HEIGHT: case PER_CELL_COUNT: case PER_CELL_MIN_HEIGHT: case PER_CELL_MAX_HEIGHT: case PER_CELL_AVG_HEIGHT: case PER_CELL_HEIGHT_STD_DEV: case PER_CELL_HEIGHT_RANGE: sfIndex = cloudGrid->addScalarField(qPrintable(GetDefaultFieldName(exportedFields[i]))); break; default: assert(false); break; } if (sfIndex < 0) { ccLog::Warning("[Rasterize] Couldn't allocate scalar field(s)! Try to free some memory ..."); break; } exportedSFs[i] = cloudGrid->getScalarField(sfIndex); assert(exportedSFs[i]); } } //the resampled cloud already contains the points corresponding to 'filled' cells so we will only //need to add the empty ones (if requested) if ((!resampleInputCloud || fillEmptyCells) && !cloudGrid->reserve(pointsCount)) { ccLog::Warning("[Rasterize] Not enough memory!"); delete cloudGrid; return 0; } //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 ccBBox box = getCustomBBox(); assert(box.isValid()); //we work with doubles as grid step can be much smaller than the cloud coordinates! double Py = box.minCorner().u[Y]; //as the 'non empty cells points' are already in the cloud //we must take care of where we put the scalar fields values! unsigned nonEmptyCellIndex = 0; for (unsigned j=0; j<m_grid.height; ++j) { const RasterCell* aCell = m_grid.data[j]; double Px = box.minCorner().u[X]; for (unsigned i=0; i<m_grid.width; ++i,++aCell) { if (aCell->h == aCell->h) //valid cell { //if we haven't resampled the original cloud, we must add the point //corresponding to this non-empty cell if (!resampleInputCloud || aCell->nbPoints == 0) { CCVector3 Pf( static_cast<PointCoordinateType>(Px), static_cast<PointCoordinateType>(Py), static_cast<PointCoordinateType>(aCell->h) ); cloudGrid->addPoint(Pf); } //fill the associated SFs assert(exportedSFs.size() >= exportedFields.size()); assert(!inputCloud || nonEmptyCellIndex < inputCloud->size()); for (size_t i=0; i<exportedSFs.size(); ++i) { CCLib::ScalarField* sf = exportedSFs[i]; ScalarType sVal = NAN_VALUE; switch (exportedFields[i]) { case PER_CELL_HEIGHT: sVal = static_cast<ScalarType>(aCell->h); break; case PER_CELL_COUNT: sVal = static_cast<ScalarType>(aCell->nbPoints); break; case PER_CELL_MIN_HEIGHT: sVal = static_cast<ScalarType>(aCell->minHeight); break; case PER_CELL_MAX_HEIGHT: sVal = static_cast<ScalarType>(aCell->maxHeight); break; case PER_CELL_AVG_HEIGHT: sVal = static_cast<ScalarType>(aCell->avgHeight); break; case PER_CELL_HEIGHT_STD_DEV: sVal = static_cast<ScalarType>(aCell->stdDevHeight); break; case PER_CELL_HEIGHT_RANGE: sVal = static_cast<ScalarType>(aCell->maxHeight - aCell->minHeight); break; default: assert(false); break; } if (resampleInputCloud) sf->setValue(nonEmptyCellIndex,sVal); else sf->addElement(sVal); } ++nonEmptyCellIndex; } else if (fillEmptyCells) //empty cell { //even if we have resampled the original cloud, we must add the point //corresponding to this empty cell { CCVector3 Pf( static_cast<PointCoordinateType>(Px), static_cast<PointCoordinateType>(Py), static_cast<PointCoordinateType>(emptyCellsHeight) ); cloudGrid->addPoint(Pf); } assert(exportedSFs.size() == exportedFields.size()); for (size_t i=0; i<exportedSFs.size(); ++i) { if (!exportedSFs[i]) { continue; } if (exportedFields[i] == PER_CELL_HEIGHT) { //we set the point height to the default height ScalarType s = static_cast<ScalarType>(emptyCellsHeight); exportedSFs[i]->addElement(s); } else { exportedSFs[i]->addElement(NAN_VALUE); } } } Px += m_grid.gridStep; } Py += m_grid.gridStep; } assert(exportedSFs.size() == exportedFields.size()); for (size_t i=0; i<exportedSFs.size(); ++i) { CCLib::ScalarField* sf = exportedSFs[i]; if (sf) { sf->computeMinAndMax(); } } //take care of former scalar fields if (!resampleInputCloud) { if (interpolateSF && inputCloud && inputCloud->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(inputCloud); for (size_t k=0; k<m_grid.scalarFields.size(); ++k) { double* _sfGrid = m_grid.scalarFields[k]; if (_sfGrid) //valid SF grid { //the corresponding SF should exist on the input cloud ccScalarField* formerSf = static_cast<ccScalarField*>(pc->getScalarField(static_cast<int>(k))); assert(formerSf); //we try to create an equivalent SF on the output grid int sfIdx = cloudGrid->addScalarField(formerSf->getName()); if (sfIdx < 0) //if we aren't lucky, the input cloud already had a SF with CC_HEIGHT_GRID_FIELD_NAME as name sfIdx = cloudGrid->addScalarField(qPrintable(QString(formerSf->getName()).append(".old"))); if (sfIdx < 0) { ccLog::Warning("[Rasterize] Couldn't allocate a new scalar field for storing SF '%s' values! Try to free some memory ...",formerSf->getName()); } else { ccScalarField* sf = static_cast<ccScalarField*>(cloudGrid->getScalarField(sfIdx)); assert(sf); //set sf values unsigned n = 0; const ScalarType emptyCellSFValue = CCLib::ScalarField::NaN(); for (unsigned j=0; j<m_grid.height; ++j) { const RasterCell* aCell = m_grid.data[j]; for (unsigned i=0; i<m_grid.width; ++i, ++_sfGrid, ++aCell) { if (aCell->nbPoints) { ScalarType s = static_cast<ScalarType>(*_sfGrid); sf->setValue(n++,s); } else if (fillEmptyCells) { sf->setValue(n++,emptyCellSFValue); } } } sf->computeMinAndMax(); sf->importParametersFrom(formerSf); assert(sf->currentSize() == pointsCount); } } } } } else { for (size_t k=0; k<cloudGrid->getNumberOfScalarFields(); ++k) { CCLib::ScalarField* sf = cloudGrid->getScalarField(static_cast<int>(k)); sf->resize(cloudGrid->size(),true,NAN_VALUE); } } QString gridName = QString("raster(%1)").arg(m_grid.gridStep); if (inputCloud) { gridName.prepend(inputCloud->getName() + QString(".")); } cloudGrid->setName(gridName); return cloudGrid; }
ccRasterizeTool::ccRasterizeTool(ccGenericPointCloud* cloud, QWidget* parent/*=0*/) : QDialog(parent, Qt::WindowMaximizeButtonHint) , cc2Point5DimEditor() , Ui::RasterizeToolDialog() , m_cloud(cloud) { setupUi(this); #ifndef CC_GDAL_SUPPORT generateRasterPushButton->setDisabled(true); generateRasterPushButton->setChecked(false); #endif connect(buttonBox, SIGNAL(accepted()), this, SLOT(testAndAccept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(testAndReject())); connect(gridStepDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateGridInfo())); connect(gridStepDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(gridOptionChanged())); connect(emptyValueDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(gridOptionChanged())); connect(resampleCloudCheckBox, SIGNAL(toggled(bool)), this, SLOT(gridOptionChanged())); connect(dimensionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionDirChanged(int))); connect(heightProjectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionTypeChanged(int))); connect(scalarFieldProjection, SIGNAL(currentIndexChanged(int)), this, SLOT(sfProjectionTypeChanged(int))); connect(fillEmptyCellsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(fillEmptyCellStrategyChanged(int))); connect(updateGridPushButton, SIGNAL(clicked()), this, SLOT(updateGridAndDisplay())); connect(generateCloudPushButton, SIGNAL(clicked()), this, SLOT(generateCloud())); connect(generateImagePushButton, SIGNAL(clicked()), this, SLOT(generateImage())); connect(generateRasterPushButton, SIGNAL(clicked()), this, SLOT(generateRaster())); connect(generateASCIIPushButton, SIGNAL(clicked()), this, SLOT(generateASCIIMatrix())); connect(generateMeshPushButton, SIGNAL(clicked()), this, SLOT(generateMesh())); connect(generateContoursPushButton, SIGNAL(clicked()), this, SLOT(generateContours())); connect(exportContoursPushButton, SIGNAL(clicked()), this, SLOT(exportContourLines())); connect(clearContoursPushButton, SIGNAL(clicked()), this, SLOT(removeContourLines())); connect(activeLayerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(activeLayerChanged(int))); //custom bbox editor ccBBox gridBBox = m_cloud ? m_cloud->getOwnBB() : ccBBox(); if (gridBBox.isValid()) { createBoundingBoxEditor(gridBBox, this); connect(editGridToolButton, SIGNAL(clicked()), this, SLOT(showGridBoxEditor())); } else { editGridToolButton->setEnabled(false); } if (m_cloud) { cloudNameLabel->setText(m_cloud->getName()); pointCountLabel->setText(QString::number(m_cloud->size())); interpolateSFFrame->setEnabled(cloud->hasScalarFields()); //populate layer box activeLayerComboBox->addItem(GetDefaultFieldName(PER_CELL_HEIGHT)); if (cloud->isA(CC_TYPES::POINT_CLOUD) && cloud->hasScalarFields()) { ccPointCloud* pc = static_cast<ccPointCloud*>(cloud); for (unsigned i=0; i<pc->getNumberOfScalarFields(); ++i) activeLayerComboBox->addItem(pc->getScalarField(i)->getName()); } else { activeLayerComboBox->setEnabled(false); } //add window create2DView(mapFrame); } loadSettings(); updateGridInfo(); gridIsUpToDate(false); }