14 #ifndef CV_GDAL_SUPPORT
33 #include <QFileDialog>
35 #include <QMessageBox>
36 #include <QPushButton>
46 : QDialog(parent, Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
48 Ui::RasterizeToolDialog(),
52 #ifdef CV_GDAL_SUPPORT
53 ignoreContourBordersCheckBox->setVisible(
false);
55 generateRasterPushButton->setDisabled(
true);
56 generateRasterPushButton->setChecked(
false);
63 connect(buttonBox, &QDialogButtonBox::accepted,
this,
65 connect(buttonBox, &QDialogButtonBox::rejected,
this,
68 connect(gridStepDoubleSpinBox,
69 static_cast<void (QDoubleSpinBox::*)(
double)
>(
70 &QDoubleSpinBox::valueChanged),
72 connect(gridStepDoubleSpinBox,
73 static_cast<void (QDoubleSpinBox::*)(
double)
>(
74 &QDoubleSpinBox::valueChanged),
76 connect(emptyValueDoubleSpinBox,
77 static_cast<void (QDoubleSpinBox::*)(
double)
>(
78 &QDoubleSpinBox::valueChanged),
80 connect(dimensionComboBox,
81 static_cast<void (QComboBox::*)(
int)
>(
82 &QComboBox::currentIndexChanged),
84 connect(heightProjectionComboBox,
85 static_cast<void (QComboBox::*)(
int)
>(
86 &QComboBox::currentIndexChanged),
88 connect(scalarFieldProjection,
89 static_cast<void (QComboBox::*)(
int)
>(
90 &QComboBox::currentIndexChanged),
92 connect(fillEmptyCellsComboBox,
93 static_cast<void (QComboBox::*)(
int)
>(
94 &QComboBox::currentIndexChanged),
97 connect(resampleCloudCheckBox, &QAbstractButton::toggled,
this,
99 connect(updateGridPushButton, &QAbstractButton::clicked,
this,
101 connect(generateCloudPushButton, &QAbstractButton::clicked,
this,
103 connect(generateImagePushButton, &QAbstractButton::clicked,
this,
105 connect(generateRasterPushButton, &QAbstractButton::clicked,
this,
107 connect(generateASCIIPushButton, &QAbstractButton::clicked,
this,
109 connect(generateMeshPushButton, &QAbstractButton::clicked,
this,
111 connect(generateContoursPushButton, &QAbstractButton::clicked,
this,
113 connect(exportContoursPushButton, &QAbstractButton::clicked,
this,
115 connect(clearContoursPushButton, &QAbstractButton::clicked,
this,
118 connect(generateHillshadePushButton, &QAbstractButton::clicked,
this,
121 connect(activeLayerComboBox,
122 static_cast<void (QComboBox::*)(
int)
>(
123 &QComboBox::currentIndexChanged),
128 if (gridBBox.isValid()) {
130 connect(editGridToolButton, &QAbstractButton::clicked,
this,
133 editGridToolButton->setEnabled(
false);
137 cloudNameLabel->setText(
138 QStringLiteral(
"<b>%1</b> (%2 points)")
142 interpolateSFCheckBox->setEnabled(
true);
143 scalarFieldProjection->setEnabled(
true);
145 interpolateSFCheckBox->setChecked(
false);
146 interpolateSFCheckBox->setEnabled(
false);
147 scalarFieldProjection->setEnabled(
false);
151 activeLayerComboBox->addItem(
155 activeLayerComboBox->addItem(
"RGB", QVariant(
LAYER_RGB));
165 activeLayerComboBox->
setEnabled(activeLayerComboBox->count() > 1);
177 resize(minimumSize());
191 exportContoursPushButton->setEnabled(
false);
192 clearContoursPushButton->setEnabled(
false);
211 return gridStepDoubleSpinBox->value();
217 return generateCountSFcheckBox->isChecked();
219 return generateMinHeightSFcheckBox->isChecked();
221 return generateMaxHeightSFcheckBox->isChecked();
223 return generateAvgHeightSFcheckBox->isChecked();
225 return generateStdDevHeightSFcheckBox->isChecked();
227 return generateHeightRangeSFcheckBox->isChecked();
236 return resampleCloudCheckBox->isEnabled() &&
237 resampleCloudCheckBox->isChecked();
241 int dim = dimensionComboBox->currentIndex();
242 assert(dim >= 0 && dim < 3);
244 return static_cast<unsigned char>(dim);
248 warningResampleWithAverageLabel->setVisible(
249 resampleCloudCheckBox->isChecked() &&
258 warningResampleWithAverageLabel->setVisible(
259 resampleCloudCheckBox->isChecked() &&
275 if (activeLayerComboBox->itemData(layerIndex).toInt() ==
LAYER_SF &&
277 interpolateSFCheckBox->setChecked(
279 interpolateSFCheckBox->setEnabled(
false);
280 generateImagePushButton->setEnabled(
false);
281 generateASCIIPushButton->setEnabled(
false);
282 projectContoursOnAltCheckBox->setEnabled(
true);
286 interpolateSFCheckBox->setEnabled(
288 generateImagePushButton->setEnabled(
true);
289 generateASCIIPushButton->setEnabled(
true);
290 projectContoursOnAltCheckBox->setEnabled(
false);
295 if (activeLayerComboBox->currentData().toInt() ==
LAYER_RGB) {
299 gridLayerRangeLabel->setText(
"[0 ; 255]");
306 qPrintable(activeLayerComboBox->itemText(layerIndex)));
317 gridLayerRangeLabel->setText(
318 QString(
"%1 [%2 ; %3]")
319 .arg(layerValues.
range())
320 .arg(layerValues.
min())
321 .arg(layerValues.
max()));
322 contourStartDoubleSpinBox->setValue(layerValues.
min());
323 contourStepDoubleSpinBox->setValue(layerValues.
range() /
327 gridLayerRangeLabel->setText(
"no active layer?!");
330 gridLayerRangeLabel->setText(
"Layer not computed");
348 emptyValueDoubleSpinBox->setEnabled(active);
349 emptyValueDoubleSpinBox->setVisible(active);
356 return emptyValueDoubleSpinBox->value();
360 switch (heightProjectionComboBox->currentIndex()) {
376 if ( !interpolateSFCheckBox
385 switch (scalarFieldProjection->currentIndex()) {
403 int projType = settings.value(
"ProjectionType",
404 heightProjectionComboBox->currentIndex())
407 settings.value(
"ProjectionDim", dimensionComboBox->currentIndex())
410 settings.value(
"SfProjEnabled", interpolateSFCheckBox->isChecked())
412 int sfProjStrategy = settings.value(
"SfProjStrategy",
413 scalarFieldProjection->currentIndex())
415 int fillStrategy = settings.value(
"FillStrategy",
416 fillEmptyCellsComboBox->currentIndex())
418 double step = settings.value(
"GridStep", gridStepDoubleSpinBox->value())
421 settings.value(
"EmptyCellsHeight", emptyValueDoubleSpinBox->value())
423 bool genCountSF = settings.value(
"GenerateCountSF",
424 generateCountSFcheckBox->isChecked())
426 bool resampleCloud = settings.value(
"ResampleOrigCloud",
427 resampleCloudCheckBox->isChecked())
430 settings.value(
"MinVertexCount", minVertexCountSpinBox->value())
433 settings.value(
"IgnoreBorders",
434 ignoreContourBordersCheckBox->isChecked())
436 bool generateCountSF = settings.value(
"generateCountSF",
437 generateCountSFcheckBox->isChecked())
439 bool generateMinHeightSF =
440 settings.value(
"generateMinHeightSF",
441 generateMinHeightSFcheckBox->isChecked())
443 bool generateMaxHeightSF =
444 settings.value(
"generateMaxHeightSF",
445 generateMinHeightSFcheckBox->isChecked())
447 bool generateAbgHeightSF =
448 settings.value(
"generateAvgHeightSF",
449 generateAvgHeightSFcheckBox->isChecked())
451 bool generateStdDevHeightSF =
452 settings.value(
"generateStdDevHeightSF",
453 generateStdDevHeightSFcheckBox->isChecked())
455 bool generateHeightRangeSF =
456 settings.value(
"generateHeightRangeSF",
457 generateHeightRangeSFcheckBox->isChecked())
459 bool projectContoursOnAlt =
460 settings.value(
"projectContoursOnAlt",
461 projectContoursOnAltCheckBox->isChecked())
466 gridStepDoubleSpinBox->setValue(step);
467 heightProjectionComboBox->setCurrentIndex(projType);
468 fillEmptyCellsComboBox->setCurrentIndex(fillStrategy);
469 emptyValueDoubleSpinBox->setValue(emptyHeight);
470 dimensionComboBox->setCurrentIndex(projDim);
471 interpolateSFCheckBox->setChecked(sfProj);
472 scalarFieldProjection->setCurrentIndex(sfProjStrategy);
473 generateCountSFcheckBox->setChecked(genCountSF);
474 resampleCloudCheckBox->setChecked(resampleCloud);
475 minVertexCountSpinBox->setValue(minVertexCount);
476 ignoreContourBordersCheckBox->setChecked(ignoreBorders);
477 generateCountSFcheckBox->setChecked(generateCountSF);
478 generateMinHeightSFcheckBox->setChecked(generateMinHeightSF);
479 generateMinHeightSFcheckBox->setChecked(generateMaxHeightSF);
480 generateAvgHeightSFcheckBox->setChecked(generateAbgHeightSF);
481 generateStdDevHeightSFcheckBox->setChecked(generateStdDevHeightSF);
482 generateHeightRangeSFcheckBox->setChecked(generateHeightRangeSF);
483 projectContoursOnAltCheckBox->setChecked(projectContoursOnAlt);
489 if (QMessageBox::question(
this,
"Unsaved contour lines",
490 "Contour lines have not been exported! Do "
491 "you really want to close the tool?",
493 QMessageBox::No) == QMessageBox::No)
515 settings.setValue(
"ProjectionType",
516 heightProjectionComboBox->currentIndex());
517 settings.setValue(
"ProjectionDim", dimensionComboBox->currentIndex());
518 settings.setValue(
"SfProjEnabled", interpolateSFCheckBox->isChecked());
519 settings.setValue(
"SfProjStrategy", scalarFieldProjection->currentIndex());
520 settings.setValue(
"FillStrategy", fillEmptyCellsComboBox->currentIndex());
521 settings.setValue(
"GridStep", gridStepDoubleSpinBox->value());
522 settings.setValue(
"EmptyCellsHeight", emptyValueDoubleSpinBox->value());
523 settings.setValue(
"GenerateCountSF", generateCountSFcheckBox->isChecked());
524 settings.setValue(
"ResampleOrigCloud", resampleCloudCheckBox->isChecked());
525 settings.setValue(
"MinVertexCount", minVertexCountSpinBox->value());
526 settings.setValue(
"IgnoreBorders",
527 ignoreContourBordersCheckBox->isChecked());
528 settings.setValue(
"generateCountSF", generateCountSFcheckBox->isChecked());
529 settings.setValue(
"generateMinHeightSF",
530 generateMinHeightSFcheckBox->isChecked());
531 settings.setValue(
"generateMaxHeightSF",
532 generateMinHeightSFcheckBox->isChecked());
533 settings.setValue(
"generateAvgHeightSF",
534 generateAvgHeightSFcheckBox->isChecked());
535 settings.setValue(
"generateStdDevHeightSF",
536 generateStdDevHeightSFcheckBox->isChecked());
537 settings.setValue(
"generateHeightRangeSF",
538 generateHeightRangeSFcheckBox->isChecked());
539 settings.setValue(
"projectContoursOnAlt",
540 projectContoursOnAltCheckBox->isChecked());
547 updateGridPushButton->setStyleSheet(QString());
550 updateGridPushButton->setStyleSheet(
551 "color: white; background-color:red;");
553 updateGridPushButton->setDisabled(state);
555 tabWidget->setEnabled(state);
559 const std::vector<ccRasterGrid::ExportableFields>& exportedFields,
562 bool copyHillshadeSF,
563 QString activeSFName,
564 bool exportToOriginalCS)
const {
568 double emptyCellsHeight = 0;
583 fillEmptyCellsStrategy !=
585 emptyCellsHeight, exportToOriginalCS);
590 if (copyHillshadeSF) {
593 if (hillshadeSFIdx >= 0) {
601 }
catch (
const std::bad_alloc&) {
603 "[Rasterize] Not enough memory to export the "
613 cloudGrid->
showSF(activeSFIndex >= 0);
614 if (activeSFIndex < 0 && cloudGrid->getNumberOfScalarFields() != 0) {
635 if (hillshadeIndex >= 0) {
636 if (activeLayerComboBox->currentIndex() == hillshadeIndex &&
637 activeLayerComboBox->count() > 1) {
638 activeLayerComboBox->setCurrentIndex(0);
640 activeLayerComboBox->removeItem(hillshadeIndex);
654 bool activeLayerIsSF =
655 (activeLayerComboBox->currentData().toInt() ==
LAYER_SF);
656 bool activeLayerIsRGB =
657 (activeLayerComboBox->currentData().toInt() ==
LAYER_RGB);
665 std::vector<ccRasterGrid::ExportableFields> exportedFields;
670 QString activeLayerName = activeLayerComboBox->currentText();
675 false, activeLayerName,
false);
676 }
catch (
const std::bad_alloc&) {
718 volumeLabel->setText(
"0");
719 filledCellsPercentageLabel->setText(
"0 %");
722 unsigned gridWidth = 0, gridHeight = 0;
728 unsigned gridTotalSize = gridWidth * gridHeight;
729 if (gridTotalSize == 1) {
730 if (QMessageBox::question(
this,
"Unexpected grid size",
731 "The generated grid will only have 1 cell! "
732 "Do you want to proceed anyway?",
734 QMessageBox::No) == QMessageBox::No)
736 }
else if (gridTotalSize > 10000000) {
737 if (QMessageBox::question(
738 this,
"Big grid size",
739 "The generated grid will have more than 10.000.000 cells! "
740 "Do you want to proceed anyway?",
741 QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
749 assert(gridStep != 0);
753 if (!
m_grid.
init(gridWidth, gridHeight, gridStep, minCorner)) {
772 unsigned filledCellCount = 0;
776 if (std::isfinite(row[i].h)) {
783 if (filledCellCount) {
785 volumeLabel->setText(QString::number(hSum * cellArea));
786 filledCellsPercentageLabel->setText(
787 QString::number(
static_cast<double>(100 * filledCellCount) /
794 CVLog::Print(QString(
"[Rasterize] Current raster grid:\n\tSize: %1 x "
795 "%2\n\tHeight values: [%3 ; %4]")
810 std::vector<ccRasterGrid::ExportableFields> exportedFields;
825 }
catch (
const std::bad_alloc&) {
829 QString activeLayerName = activeLayerComboBox->currentText();
830 bool activeLayerIsSF =
831 (activeLayerComboBox->currentData().toInt() ==
LAYER_SF);
841 true, activeLayerName,
true);
843 if (rasterCloud && autoExport) {
852 "[Rasterize] Previously selected entity (source cloud) has "
858 mainWindow->
addToDB(rasterCloud);
859 CVLog::Print(QString(
"[Rasterize] Cloud '%1' successfully exported")
873 std::string errorStr;
878 IGNORE_MAX_EDGE_LENGTH,
882 rasterMesh =
new ccMesh(baseMesh, rasterCloud);
891 rasterCloud->
setName(
"vertices");
900 CVLog::Print(QString(
"[Rasterize] Mesh '%1' successfully exported")
904 .arg(QString::fromStdString(errorStr)));
909 #ifdef CV_GDAL_SUPPORT
911 #include <cpl_string.h>
913 #include <gdal_alg.h>
914 #include <gdal_priv.h>
917 #include "ui_rasterExportOptionsDlg.h"
922 class RasterExportOptionsDlg :
public QDialog,
923 public Ui::RasterExportOptionsDialog {
925 explicit RasterExportOptionsDlg(QWidget* parent = 0)
926 : QDialog(parent, Qt::Tool),
Ui::RasterExportOptionsDialog() {
934 #ifdef CV_GDAL_SUPPORT
941 int visibleSfIndex = -1;
942 if (activeLayerComboBox->currentData().toInt() ==
LAYER_SF &&
947 qPrintable(activeLayerComboBox->currentText()));
952 exportBands.
height =
true;
953 exportBands.
rgb =
false;
955 RasterExportOptionsDlg reoDlg;
956 reoDlg.dimensionsLabel->setText(
959 reoDlg.exportRGBCheckBox->setChecked(exportBands.
rgb);
960 reoDlg.exportHeightsCheckBox->setChecked(exportBands.
height);
961 reoDlg.exportDensityCheckBox->setChecked(exportBands.
density);
962 reoDlg.exportActiveLayerCheckBox->setChecked(exportBands.
visibleSF);
963 reoDlg.exportActiveLayerCheckBox->setEnabled(visibleSfIndex >= 0);
964 reoDlg.exportAllSFCheckBox->setEnabled(hasScalarFields);
965 reoDlg.exportAllSFCheckBox->setChecked(exportBands.
allSFs);
968 if (!reoDlg.exec()) {
974 if (reoDlg.exportRGBCheckBox->isEnabled() &&
975 reoDlg.exportRGBCheckBox->isChecked() &&
976 (reoDlg.exportHeightsCheckBox->isChecked() ||
977 reoDlg.exportDensityCheckBox->isChecked() ||
978 reoDlg.exportActiveLayerCheckBox->isChecked() ||
979 reoDlg.exportAllSFCheckBox->isChecked())) {
980 if (QMessageBox::warning(
982 "Mixing colors and other layers will result in\na "
983 "strange raster file with 64 bits color bands\n(some "
984 "applications won't handle them properly)",
986 QMessageBox::Retry) == QMessageBox::Ignore) {
997 QString outputFilename;
1001 QString imageSavePath =
1004 outputFilename = QFileDialog::getSaveFileName(
1006 imageSavePath + QString(
"/raster.tif"),
"geotiff (*.tif)");
1008 if (outputFilename.isNull()) {
1013 settings.setValue(
"savePathImage",
1014 QFileInfo(outputFilename).absolutePath());
1017 exportBands.
height = reoDlg.exportHeightsCheckBox->isChecked();
1018 exportBands.
rgb = reoDlg.exportRGBCheckBox->isChecked();
1019 exportBands.
density = reoDlg.exportDensityCheckBox->isChecked();
1020 exportBands.
allSFs = reoDlg.exportAllSFCheckBox->isChecked();
1021 exportBands.
visibleSF = reoDlg.exportActiveLayerCheckBox->isChecked();
1032 "[Rasterize] GDAL not supported by this version! Can't generate a "
1039 QString outputFilename,
1045 double customHeightForEmptyCells
1048 int visibleSfIndex ) {
1049 #ifdef CV_GDAL_SUPPORT
1051 if (exportBands.
visibleSF && visibleSfIndex < 0) {
1058 const unsigned char X = Z == 2 ? 0 : Z + 1;
1059 const unsigned char Y =
X == 2 ? 0 :
X + 1;
1065 double shiftZ = 0.0;
1071 shiftX -= shift.
u[
X];
1072 shiftY -= shift.
u[Y];
1073 shiftZ -= shift.
u[Z];
1082 bool onlyRGBA =
true;
1084 if (exportBands.
height) {
1089 bool rgbaMode =
false;
1090 if (exportBands.
rgb) {
1106 if (exportBands.
allSFs) {
1107 for (
size_t i = 0; i < grid.
scalarFields.size(); ++i) {
1113 }
else if (exportBands.
visibleSF && visibleSfIndex >= 0) {
1118 if (totalBands == 0) {
1120 "Can't output a raster with no band! (check export "
1127 GetGDALDriverManager()->GetDriverCount());
1129 const char pszFormat[] =
"GTiff";
1130 GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
1132 CVLog::Error(
"[GDAL] Driver %s is not supported", pszFormat);
1136 char** papszMetadata = poDriver->GetMetadata();
1137 if (!CSLFetchBoolean(papszMetadata, GDAL_DCAP_CREATE,
FALSE)) {
1138 CVLog::Error(
"[GDAL] Driver %s doesn't support Create() method",
1143 char** papszOptions =
nullptr;
1144 GDALDataset* poDstDS = poDriver->Create(
1145 qPrintable(outputFilename),
static_cast<int>(grid.
width),
1146 static_cast<int>(grid.
height), totalBands,
1147 onlyRGBA ? GDT_Byte : GDT_Float64, papszOptions);
1151 "[GDAL] Failed to create output raster (not enough memory?)");
1155 poDstDS->SetMetadataItem(
"AREA_OR_POINT",
"AREA");
1157 double adfGeoTransform[6] = {
1166 poDstDS->SetGeoTransform(adfGeoTransform);
1176 int currentBand = 0;
1179 if (exportBands.
rgb) {
1180 GDALRasterBand* rgbBands[3] = {poDstDS->GetRasterBand(++currentBand),
1181 poDstDS->GetRasterBand(++currentBand),
1182 poDstDS->GetRasterBand(++currentBand)};
1183 rgbBands[0]->SetColorInterpretation(GCI_RedBand);
1184 rgbBands[1]->SetColorInterpretation(GCI_GreenBand);
1185 rgbBands[2]->SetColorInterpretation(GCI_BlueBand);
1187 unsigned char* cLine =
1188 (
unsigned char*)CPLMalloc(
sizeof(
unsigned char) * grid.
width);
1198 for (
unsigned k = 0; k < 3; ++k) {
1199 rgbBands[k]->SetStatistics(
1203 for (
unsigned j = 0; j < grid.
height; ++j) {
1208 for (
unsigned i = 0; i < grid.
width; ++i) {
1209 cLine[i] = (std::isfinite(row[i].h)
1210 ?
static_cast<unsigned char>(
std::max(
1213 row[i].
color.u[k])))
1217 if (rgbBands[k]->RasterIO(GF_Write, 0,
static_cast<int>(j),
1218 static_cast<int>(grid.
width), 1,
1219 cLine,
static_cast<int>(grid.
width),
1220 1, GDT_Byte, 0, 0) != CE_None) {
1229 if (!
error && rgbaMode) {
1230 GDALRasterBand* aBand = poDstDS->GetRasterBand(++currentBand);
1231 aBand->SetColorInterpretation(GCI_AlphaBand);
1232 aBand->SetStatistics(
1236 for (
unsigned j = 0; j < grid.
height; ++j) {
1238 for (
unsigned i = 0; i < grid.
width; ++i) {
1239 cLine[i] = (std::isfinite(row[i].h) ? 255 : 0);
1242 if (aBand->RasterIO(GF_Write, 0,
static_cast<int>(j),
1243 static_cast<int>(grid.
width), 1, cLine,
1244 static_cast<int>(grid.
width), 1, GDT_Byte,
1256 "[GDAL] An error occurred while writing the color bands!");
1262 double* scanline = (
double*)CPLMalloc(
sizeof(
double) * grid.
width);
1270 if (exportBands.
height) {
1271 GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);
1273 poBand->SetColorInterpretation(GCI_Undefined);
1275 double emptyCellHeight = 0;
1276 switch (fillEmptyCellsStrategy) {
1279 poBand->SetNoDataValue(
1290 emptyCellHeight = customHeightForEmptyCells;
1299 emptyCellHeight += shiftZ;
1301 for (
unsigned j = 0; j < grid.
height; ++j) {
1303 for (
unsigned i = 0; i < grid.
width; ++i) {
1304 scanline[i] = std::isfinite(row[i].h) ? row[i].h + shiftZ
1308 if (poBand->RasterIO(GF_Write, 0,
static_cast<int>(j),
1309 static_cast<int>(grid.
width), 1, scanline,
1310 static_cast<int>(grid.
width), 1, GDT_Float64,
1313 "[GDAL] An error occurred while writing the height "
1315 if (scanline) CPLFree(scanline);
1324 GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);
1326 poBand->SetColorInterpretation(GCI_Undefined);
1327 for (
unsigned j = 0; j < grid.
height; ++j) {
1329 for (
unsigned i = 0; i < grid.
width; ++i) {
1330 scanline[i] = row[i].nbPoints;
1333 if (poBand->RasterIO(GF_Write, 0,
static_cast<int>(j),
1334 static_cast<int>(grid.
width), 1, scanline,
1335 static_cast<int>(grid.
width), 1, GDT_Float64,
1338 "[GDAL] An error occurred while writing the height "
1340 if (scanline) CPLFree(scanline);
1348 if (exportBands.
allSFs || (exportBands.
visibleSF && visibleSfIndex >= 0)) {
1349 for (
size_t k = 0; k < grid.
scalarFields.size(); ++k) {
1352 visibleSfIndex ==
static_cast<int>(k))) {
1354 GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);
1356 double sfNanValue = std::numeric_limits<
1357 ccRasterGrid::SF::value_type>::quiet_NaN();
1358 poBand->SetNoDataValue(sfNanValue);
1360 poBand->SetColorInterpretation(GCI_Undefined);
1362 for (
unsigned j = 0; j < grid.
height; ++j) {
1365 const double* sfRow =
1367 for (
unsigned i = 0; i < grid.
width; ++i) {
1368 scanline[i] = row[i].nbPoints ? sfRow[i] : sfNanValue;
1371 if (poBand->RasterIO(GF_Write, 0,
static_cast<int>(j),
1372 static_cast<int>(grid.
width), 1,
1373 scanline,
static_cast<int>(grid.
width),
1374 1, GDT_Float64, 0, 0) != CE_None) {
1377 QString(
"[GDAL] An error occurred while "
1378 "writing a scalar field band!"));
1387 if (scanline) CPLFree(scanline);
1393 CVLog::Print(QString(
"[Rasterize] Raster '%1' successfully saved")
1394 .arg(outputFilename));
1400 "[Rasterize] GDAL not supported by this version! Can't generate a "
1410 CVLog::Error(
"Need a valid raster/cloud to compute contours!");
1429 hillshadeLayer =
nullptr;
1435 activeLayerComboBox->setEnabled(
true);
1437 assert(hillshadeLayer &&
1445 int zenith_deg = sunZenithSpinBox->value();
1448 double cos_zenith_rad = cos(zenith_rad);
1449 double sin_zenith_rad = sin(zenith_rad);
1451 int azimuth_deg = sunAzimuthSpinBox->value();
1452 int azimuth_math = 360 - azimuth_deg + 90;
1456 unsigned validCellIndex = 0;
1457 for (
unsigned j = (sparseSF ? 0 : 1); j <
m_grid.
height - 1; ++j) {
1460 for (
unsigned i = sparseSF ? 0 : 1; i <
m_grid.
width; ++i) {
1462 if (std::isfinite(row[i].h)) {
1465 int dz_dx_count = 0;
1467 int dz_dy_count = 0;
1469 for (
int di = -1; di <= 1; ++di) {
1470 for (
int dj = -1; dj <= 1; ++dj) {
1481 int dx_weight = (dj == 0 ? 2 : 1);
1482 dz_dx += (di < 0 ? -1.0 : 1.0) * dx_weight *
1484 dz_dx_count += dx_weight;
1488 int dy_weight = (di == 0 ? 2 : 1);
1489 dz_dy += (dj < 0 ? -1.0 : 1.0) * dy_weight *
1491 dz_dy_count += dy_weight;
1499 if (dz_dx_count == 8 && dz_dy_count == 8) {
1503 double slope_rad = atan( sqrt(
1504 dz_dx * dz_dx + dz_dy * dz_dy));
1506 double aspect_rad = 0;
1507 static const double s_zero = 1.0e-8;
1508 if (
fabs(dz_dx) > s_zero) {
1509 aspect_rad = atan2(dz_dy, -dz_dx);
1510 if (aspect_rad < 0) {
1511 aspect_rad += 2.0 *
M_PI;
1515 if (dz_dy > s_zero) {
1516 aspect_rad = 0.5 *
M_PI;
1517 }
else if (dz_dy < s_zero) {
1518 aspect_rad = 1.5 *
M_PI;
1522 ScalarType hillshade =
static_cast<ScalarType
>(
std::max(
1524 cos_zenith_rad * cos(slope_rad) +
1525 sin_zenith_rad * sin(slope_rad) *
1526 cos(azimuth_rad - aspect_rad)));
1543 activeLayerComboBox->setCurrentIndex(
1551 #ifdef CV_GDAL_SUPPORT
1553 struct ContourGenerationParameters {
1554 std::vector<ccPolyline*> contourLines;
1556 bool projectContourOnAltitudes =
false;
1559 static CPLErr ContourWriter(
double dfLevel,
1570 ContourGenerationParameters*
params =
1571 (ContourGenerationParameters*)userData;
1580 unsigned subIndex = 0;
1581 for (
int i = 0; i < nPoints; ++i) {
1582 CCVector3 P(padfX[i], padfY[i], dfLevel);
1584 if (
params->projectContourOnAltitudes) {
1586 static_cast<int>(
params->grid->width) - 1);
1588 static_cast<int>(
params->grid->height) - 1);
1589 double h =
params->grid->rows[yi][xi].h;
1590 if (std::isfinite(h)) {
1595 if (poly->
size() < 2) {
1597 params->contourLines.pop_back();
1619 if (!vertices->
reserve(nPoints - i) ||
1620 !poly->
reserve(nPoints - i)) {
1628 params->contourLines.push_back(poly);
1629 }
catch (
const std::bad_alloc&) {
1646 unsigned subIndex) {
1648 if (poly->
size() > 1) {
1649 poly->
setName(QString(
"Contour line value = %1 (#%2)")
1654 poly->
setWidth(contourWidthSpinBox->value() < 2
1656 : contourWidthSpinBox
1661 if (colorizeContoursCheckBox->isChecked()) {
1682 CVLog::Error(
"Need a valid raster/cloud to compute contours!");
1687 bool projectContourOnAltitudes =
false;
1689 switch (activeLayerComboBox->currentData().toInt()) {
1694 CVLog::Error(
"Can't generate contours from RGB colors");
1697 projectContourOnAltitudes =
1698 projectContoursOnAltCheckBox->isChecked();
1710 const double emptyCellsValue = activeLayer->
getMin() - 1.0;
1713 double startValue = contourStartDoubleSpinBox->value();
1714 if (startValue > activeLayer->
getMax()) {
1715 CVLog::Error(
"Start value is above the layer maximum value!");
1720 double step = contourStepDoubleSpinBox->value();
1722 unsigned levelCount =
1723 1 +
static_cast<unsigned>(
1724 floor((activeLayer->
getMax() - startValue) / step));
1727 int minVertexCount = minVertexCountSpinBox->value();
1728 assert(minVertexCount >= 3);
1732 bool memoryError =
false;
1734 #ifdef CV_GDAL_SUPPORT
1738 ContourGenerationParameters
params;
1740 params.projectContourOnAltitudes = projectContourOnAltitudes;
1741 GDALContourGeneratorH hCG =
1743 step, startValue, ContourWriter, &
params);
1745 CVLog::Error(
"[GDAL] Failed to create contour generator");
1751 double* scanline = (
double*)CPLMalloc(
sizeof(
double) *
m_grid.
width);
1759 unsigned layerIndex = 0;
1764 if (cellRow[i].nbPoints || !sparseLayer) {
1765 ScalarType value = activeLayer->
getValue(layerIndex++);
1771 scanline[i] = emptyCellsValue;
1775 CPLErr
error = GDAL_CG_FeedLine(hCG, scanline);
1776 if (
error != CE_None) {
1778 "[GDAL] An error occurred during countour lines "
1790 if (!
params.contourLines.empty()) {
1794 const unsigned char X = Z == 2 ? 0 : Z + 1;
1795 const unsigned char Y =
X == 2 ? 0 :
X + 1;
1802 if (
static_cast<int>(poly->
size()) < minVertexCount) {
1808 double height = std::numeric_limits<double>::quiet_NaN();
1809 for (
unsigned i = 0; i < poly->
size(); ++i) {
1836 params.contourLines.resize(0);
1842 bool ignoreBorders = ignoreContourBordersCheckBox->isChecked();
1847 if (!ignoreBorders) {
1852 std::vector<double> grid;
1854 grid.resize(xDim * yDim, 0);
1855 }
catch (
const std::bad_alloc&) {
1866 unsigned layerIndex = 0;
1869 double* row = &(grid[(j + margin) * xDim + margin]);
1871 if (cellRow[i].nbPoints || !sparseLayer) {
1872 ScalarType value = activeLayer->
getValue(layerIndex++);
1876 row[i] = emptyCellsValue;
1884 if (!ignoreBorders) {
1894 const unsigned char X = (Z == 2 ? 0 : Z + 1);
1895 const unsigned char Y = (
X == 2 ? 0 :
X + 1);
1899 pDlg.
setInfo(tr(
"Levels: %1\nCells: %2 x %3")
1905 QApplication::processEvents();
1908 int lineWidth = contourWidthSpinBox->value();
1909 bool colorize = colorizeContoursCheckBox->isChecked();
1911 double v = startValue;
1912 while (v <= activeLayer->getMax() && !memoryError) {
1915 int lineCount = iso.
find(grid.data());
1918 QString(
"[Rasterize][Isolines] value=%1 : %2 lines")
1924 for (
int i = 0; i < lineCount; ++i) {
1926 if (vertCount >= minVertexCount) {
1929 while (startVi < vertCount) {
1935 if (poly->
reserve(vertCount - startVi) &&
1936 vertices->
reserve(vertCount - startVi)) {
1937 unsigned localIndex = 0;
1938 for (
int vi = startVi; vi < vertCount; ++vi) {
1958 if (projectContourOnAltitudes) {
1967 if (std::isfinite(h)) {
1981 assert(localIndex < vertices->
size());
1986 if (poly->
size() > 1) {
2021 }
catch (
const std::bad_alloc&) {
2026 CVLog::Print(QString(
"[Rasterize] %1 iso-lines generated (%2 levels)")
2034 exportContoursPushButton->setEnabled(
true);
2035 clearContoursPushButton->setEnabled(
true);
2051 bool colorize = colorizeContoursCheckBox->isChecked();
2056 const unsigned char X = (Z == 2 ? 0 : Z + 1);
2057 const unsigned char Y = (
X == 2 ? 0 :
X + 1);
2060 new ccHObject(QString(
"Contour plot(%1) [step=%2]")
2062 .arg(contourStepDoubleSpinBox->value()));
2071 if (vertices && Z != 2) {
2072 for (
unsigned j = 0; j < vertices->
size(); ++j) {
2089 exportContoursPushButton->setEnabled(
false);
2094 CVLog::Print(QString(
"Contour lines have been successfully exported to DB "
2100 double& emptyCellsHeight,
double& minHeight,
double& maxHeight)
const {
2104 emptyCellsHeight = 0.0;
2108 switch (fillEmptyCellsStrategy) {
2125 minHeight = customEmptyCellsHeight;
2127 maxHeight = customEmptyCellsHeight;
2128 emptyCellsHeight = customEmptyCellsHeight;
2141 return fillEmptyCellsStrategy;
2148 double emptyCellsHeight = 0;
2157 if (!bitmap8.isNull()) {
2158 bool addTransparentColor =
2162 QVector<QRgb> palette(256);
2168 unsigned steps = (addTransparentColor ? 255 : 256);
2169 for (
unsigned i = 0; i < steps; i++) {
2170 const ecvColor::Rgb* col = colorScale->getColorByRelativePos(
2171 i /
static_cast<double>(steps - 1), steps,
2173 palette[i] = qRgba(col->
r, col->
g, col->
b, 255);
2176 for (
unsigned i = 0; i < 256; i++) {
2177 palette[i] = qRgba(i, i, i, 255);
2181 double maxColorComp =
2183 if (addTransparentColor) {
2184 palette[255] = qRgba(255, 0, 255,
2187 maxColorComp = 254.99;
2190 bitmap8.setColorTable(palette);
2193 unsigned emptyCellColorIndex = 0;
2194 switch (fillEmptyCellsStrategy) {
2196 emptyCellColorIndex = 255;
2199 emptyCellColorIndex = 0;
2202 emptyCellColorIndex = 255;
2205 double normalizedHeight = (emptyCellsHeight - minHeight) /
2206 (maxHeight - minHeight);
2209 assert(normalizedHeight >= 0.0 && normalizedHeight <= 1.0);
2210 emptyCellColorIndex =
static_cast<unsigned>(
2211 floor(normalizedHeight * maxColorComp));
2218 double range = maxHeight - minHeight;
2227 if (std::isfinite(row[i].h)) {
2228 double normalizedHeight = (row[i].h - minHeight) / range;
2229 assert(normalizedHeight >= 0.0 && normalizedHeight <= 1.0);
2230 unsigned char val =
static_cast<unsigned char>(
2231 floor(normalizedHeight * maxColorComp));
2236 emptyCellColorIndex);
2253 if (!outputFilename.isNull())
2256 settings.setValue(
"savePathImage", QFileInfo(outputFilename).absolutePath());
2257 settings.endGroup();
2259 if (bitmap8.save(outputFilename))
2261 CVLog::Print(QString(
"[Rasterize] Image '%1' successfully saved").arg(outputFilename));
2271 CVLog::Error(
"Failed to create output image! (not enough memory?)");
2280 QString asciiGridSavePath =
2285 QString filter(
"ASCII file (*.txt)");
2286 QString outputFilename = QFileDialog::getSaveFileName(
2287 0,
"Save grid as ASCII file",
2288 asciiGridSavePath + QString(
"/raster_matrix.txt"), filter);
2289 if (outputFilename.isNull())
return;
2291 FILE* pFile = fopen(qPrintable(outputFilename),
"wt");
2294 QString(
"[ccHeightGridGeneration] Failed to write '%1' file!")
2295 .arg(outputFilename));
2299 double emptyCellsHeight = 0;
2307 fprintf(pFile,
"%.8f ",
2308 std::isfinite(row[i].h) ? row[i].h : emptyCellsHeight);
2311 fprintf(pFile,
"\n");
2318 settings.setValue(
"savePathASCIIGrid",
2319 QFileInfo(outputFilename).absolutePath());
2321 CVLog::Print(QString(
"[Rasterize] Raster matrix '%1' successfully saved")
2322 .arg(outputFilename));
constexpr ScalarType NAN_VALUE
NaN as a ScalarType value.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
cmdLineReadable * params[]
virtual void release()
Decrease counter and deletes object when 0.
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
static QString GetSaveFilename(const QString &dialogTitle, const QString &baseName, const QString &imageSavePath, QWidget *parentWidget=nullptr)
Helper: select an output image filename.
int getContourLength(int contour) const
Returns the length of a given contour.
void setThreshold(T t)
Sets isoline value to trace.
double getContourY(int contour, int v) const
void createOnePixelBorder(T *in, T borderval) const
Creates a single pixel, 0-valued border around the grid.
int find(const T *in)
Find isolines.
bool isContourClosed(int contour) const
Returns whether a given contour is closed or not.
double getContourX(int contour, int v) const
static MainWindow * TheInstance()
Returns the unique instance of this object.
void addToDB(const QStringList &filenames, QString fileFilter=QString(), bool displayDialog=true)
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
2.5D data editor (generic interface)
virtual ccBBox getCustomBBox() const
Returns custom bbox.
ccRasterGrid::EmptyCellFillOption getFillEmptyCellsStrategy(QComboBox *comboBox) const
Returns the empty cell strategy (for a given combo-box)
void createBoundingBoxEditor(const ccBBox &gridBBox, QWidget *parent)
Creates the bounding-box editor.
ccPointCloud * convertGridToCloud(const std::vector< ccRasterGrid::ExportableFields > &exportedFields, bool interpolateSF, bool interpolateColors, bool resampleInputCloudXY, bool resampleInputCloudZ, ccGenericPointCloud *inputCloud, bool fillEmptyCells, double emptyCellsHeight, bool exportToOriginalCS) const
Shortcut to ccRasterGrid::convertToCloud.
ccRasterGrid m_grid
Raster grid.
virtual void update2DDisplayZoom(ccBBox &box)
Updates the 2D display zoom.
ccPointCloud * m_rasterCloud
'Raster' cloud
virtual bool showGridBoxEditor()
Show grid box editor and update.
virtual QString getGridSizeAsString() const
Returns the grid size as a string.
void create2DView(QFrame *parentFrame)
Creates the 2D view.
virtual bool getGridSize(unsigned &width, unsigned &height) const
Returns the grid size.
QSharedPointer< ccColorScale > Shared
Shared pointer type.
static ccColorScale::Shared GetDefaultScale(DEFAULT_SCALES scale=BGYR)
Returns a pre-defined color scale (static shortcut)
virtual bool colorsShown() const
Returns whether colors are shown or not.
virtual bool hasColors() const
Returns whether colors are enabled or not.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool sfShown() const
Returns whether active scalar field is visible.
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
virtual bool hasScalarFields() const
Returns whether one or more scalar fields are instantiated.
A 3D cloud interface with associated features (color, normals, octree, etc.)
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Hierarchical CLOUDVIEWER Object.
virtual ccBBox getDisplayBB_recursive(bool relative)
Returns the bounding-box of this entity and it's children WHEN DISPLAYED.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
virtual QString getName() const
Returns object name.
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
bool isA(CV_CLASS_ENUM type) const
QVariant getMetaData(const QString &key) const
Returns a given associated meta data.
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
virtual bool isEnabled() const
Returns whether the object is enabled or not.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
void invalidateBoundingBox() override
Invalidates bounding box.
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
bool hasColors() const override
Returns whether colors are enabled or not.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
virtual void setGlobalShift(const CCVector3d &shift) override
Sets shift applied to original coordinates (information storage only)
static QString MetaKeyConstAltitude()
Meta data key: contour plot constant altitude (for contour plots, etc.)
virtual void setGlobalScale(double scale) override
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
void setWidth(PointCoordinateType width)
Sets the width of the line.
Scalar field range structure.
A scalar field associated to display-related parameters.
const ccColorScale::Shared & getColorScale() const
Returns associated color scale.
void setColorScale(ccColorScale::Shared scale)
Sets associated color scale.
const Range & displayRange() const
Access to the range of displayed values.
const ecvColor::Rgb * getColor(ScalarType value) const
void computeMinAndMax() override
Determines the min and max values.
virtual void setGlobalScale(double scale)
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
bool isValid() const
Returns whether bounding box is valid or not.
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
A generic mesh with index-based vertex access.
bool oneStep()
Increments total progress value of a single unit.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
const CCVector3 * getPoint(unsigned index) const override
void setClosed(bool state)
Sets whether the polyline is closed or not.
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
void invalidateBoundingBox()
Invalidates the bounding-box.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
A simple scalar field (to be associated to a point cloud)
void fill(ScalarType fillValue=0)
Fills the array with a particular value.
ScalarType getMin() const
Returns the minimum value.
ScalarType & getValue(std::size_t index)
void setValue(std::size_t index, ScalarType value)
const char * getName() const
Returns scalar field name.
bool reserveSafe(std::size_t count)
Reserves memory (no exception thrown)
static bool ValidValue(ScalarType value)
Returns whether a scalar value is valid or not.
unsigned currentSize() const
ScalarType getMax() const
Returns the maximum value.
static const QString HeightGridGeneration()
Graphical progress indicator (thread-safe)
virtual void start() override
virtual void setInfo(const char *infoStr) override
Notifies some information about the ongoing process.
virtual void setMethodTitle(const char *methodTitle) override
Notifies the algorithm title.
__host__ __device__ float2 fabs(float2 v)
static void error(char *msg)
bool interpolateColors(const ccHObject::Container &selectedEntities, QWidget *parent)
Interpolate colors from on entity and transfer them to another one.
bool interpolateSFs(const ccHObject::Container &selectedEntities, ecvMainAppInterface *app)
Interpolate scalar fields from on entity and transfer them to another one.
MiniVec< float, N > floor(const MiniVec< float, N > &a)
float DegreesToRadians(int degrees)
Convert degrees to radians.
@ DELAUNAY_2D_AXIS_ALIGNED
bool LessThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
std::string toString(T x)
constexpr Rgb darkGrey(MAX/2, MAX/2, MAX/2)
constexpr Rgb lightGrey(static_cast< ColorCompType >(MAX *0.8), static_cast< ColorCompType >(MAX *0.8), static_cast< ColorCompType >(MAX *0.8))
QString defaultDocPath()
Shortcut for getting the documents location path.
ExportableFields
Exportable fields.
unsigned validCellCount
Number of VALID cells.
ProjectionType
Types of projection.
@ INVALID_PROJECTION_TYPE
double gridStep
Grid step ('pixel' size)
std::vector< ccRasterCell > Row
Row.
unsigned height
Number of rows.
bool hasColors
Whether the (average) colors are available or not.
bool init(unsigned w, unsigned h, double gridStep, const CCVector3d &minCorner)
Initializes / resets the grid.
double meanHeight
Average height (computed on the NON-EMPTY or INTERPOLATED cells)
bool fillWith(ccGenericPointCloud *cloud, unsigned char projectionDimension, ProjectionType projectionType, bool interpolateEmptyCells, ProjectionType sfInterpolation=INVALID_PROJECTION_TYPE, ecvProgressDialog *progressDialog=nullptr)
Fills the grid with a point cloud.
std::vector< SF > scalarFields
Associated scalar fields.
static QString GetDefaultFieldName(ExportableFields field)
Returns the default name of a given field.
std::vector< Row > rows
All cells.
double maxHeight
Max height (computed on the NON-EMPTY or INTERPOLATED cells)
bool isValid() const
Returns whether the grid is 'valid' or not.
unsigned width
Number of columns.
EmptyCellFillOption
Option for handling empty cells.
double minHeight
Min height (computed on the NON-EMPTY or INTERPOLATED cells)