ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
distanceMapGenerationDlg.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 // local
11 #include "ccMapWindow.h"
12 #include "ccSymbolCloud.h"
13 #include "dxfProfilesExportDlg.h"
14 #include "dxfProfilesExporter.h"
15 
16 // ECV_PLUGINS
17 #include <ecvMainAppInterface.h>
18 
19 // qCC
20 // #include <ecvCommon.h>
21 #include <ecvColorScaleEditorDlg.h>
22 #include <ecvColorScaleSelector.h>
23 #include <ecvColorScalesManager.h>
24 #include <ecvRenderToFileDlg.h>
25 
26 // common
27 #include <ecvQtHelpers.h>
28 
29 // Qt5/Qt6 Compatibility
30 #include <QtCompat.h>
31 
32 // CV_DB_LIB
33 #include <ecvDisplayTools.h>
34 #include <ecvFileUtils.h>
35 #include <ecvPlane.h>
36 #include <ecvPointCloud.h>
37 #include <ecvPolyline.h>
38 #include <ecvScalarField.h>
39 
40 // Qt
41 #include <QColorDialog>
42 #include <QFile>
43 #include <QFileDialog>
44 #include <QFileInfo>
45 #include <QFontMetrics>
46 #include <QHBoxLayout>
47 #include <QLocale>
48 #include <QMainWindow>
49 #include <QProgressDialog>
50 #include <QSettings>
51 #include <QTextStream>
52 
53 // system
54 #include <assert.h>
55 
56 // default names
57 static const char XLABEL_CLOUD_NAME[] = "X_Labels";
58 static const char YLABEL_CLOUD_NAME[] = "Y_Labels";
59 static const double DEFAULT_LABEL_MARGIN =
60  20.0; // half of this in fact (we use the 'symbol' size)
61 
62 static double ConvertAngleFromRad(
63  double angle_rad, DistanceMapGenerationDlg::ANGULAR_UNIT destUnit) {
64  switch (destUnit) {
65  case DistanceMapGenerationDlg::ANG_DEG: // degrees
66  return cloudViewer::RadiansToDegrees(angle_rad);
67  case DistanceMapGenerationDlg::ANG_RAD: // radians
68  return angle_rad;
70  return angle_rad / M_PI * 200.0;
71  default:
72  assert(false);
73  }
74 
75  return 0.0;
76 }
77 
78 static double ConvertAngleToRad(
79  double angle, DistanceMapGenerationDlg::ANGULAR_UNIT srcUnit) {
80  switch (srcUnit) {
81  case DistanceMapGenerationDlg::ANG_DEG: // degrees
82  return cloudViewer::DegreesToRadians(angle);
83  case DistanceMapGenerationDlg::ANG_RAD: // radians
84  return angle;
86  return angle / 200.0 * M_PI;
87  default:
88  assert(false);
89  }
90 
91  return 0.0;
92 }
93 
95  ccPointCloud* cloud,
96  ccScalarField* sf,
97  ccPolyline* polyline,
98  ecvMainAppInterface* app /*=0*/)
99  : QDialog(app ? app->getMainWindow() : 0),
100  m_app(app),
101  m_cloud(cloud),
102  m_profile(polyline),
103  m_sf(sf),
104  m_map(0),
105  m_angularUnits(ANG_GRAD),
106  m_window(0),
107  m_colorScaleSelector(0),
108  m_xLabels(0),
109  m_yLabels(0),
110  m_gridColor(Qt::gray),
111  m_symbolColor(Qt::black) {
112  setupUi(this);
113 
114  assert(m_cloud && m_sf && m_profile);
115 
116  // add color ramp selector widget (before calling
117  // initFromPersistentSettings!)
118  if (m_sf) {
119  // create selector widget
121  m_app->getColorScalesManager(), this,
122  QString::fromUtf8(":/CC/plugin/qSRA/gearIcon.png"));
126  connect(m_colorScaleSelector, SIGNAL(colorScaleSelected(int)), this,
127  SLOT(colorScaleChanged(int)));
128  connect(m_colorScaleSelector, SIGNAL(colorScaleEditorSummoned()), this,
129  SLOT(spawnColorScaleEditor()));
130  // add selector to group's layout
131  if (!colorRampGroupBox->layout())
132  colorRampGroupBox->setLayout(new QHBoxLayout());
133  colorRampGroupBox->layout()->addWidget(m_colorScaleSelector);
134  colorScaleStepsSpinBox->setRange(ccColorScale::MIN_STEPS,
136  }
137 
138  // init parameters from persistent settings
140 
141  if (m_sf) {
142  // we apply the cloud current color scale ONLY if it is not a default
143  // one (otherwise we keep the default dialog's one)
144  const ccColorScale::Shared& scale = m_sf->getColorScale();
145  if (scale && !scale->isLocked())
146  m_colorScaleSelector->setSelectedScale(scale->getUuid());
147  }
148 
149  // profile meta-data
151  bool validProfile = false;
152 
153  // set default dialog values with polyline & cloud information
154  if (m_profile) {
156  m_profile, profileDesc);
157  if (validProfile) {
158  // update the 'Generatrix' tab
159  {
160  axisDimComboBox->setCurrentIndex(profileDesc.revolDim);
161 
162  xOriginDoubleSpinBox->setValue(profileDesc.origin.x);
163  yOriginDoubleSpinBox->setValue(profileDesc.origin.y);
164  zOriginDoubleSpinBox->setValue(profileDesc.origin.z);
165  }
166 
168  } else {
169  if (m_app)
170  m_app->dispToConsole(QString("Invalid profile: can't generate "
171  "a proper map!"),
173  }
174  }
175 
176  // compute min and max height of the points
177  // we will 'lock" the max height value with that information
178  if (m_cloud) {
179  ccBBox bbox = m_cloud->getOwnBB();
180  PointCoordinateType hMin = 0, hMax = 0;
181  if (bbox.isValid()) {
182  hMin = bbox.minCorner().u[profileDesc.revolDim];
183  hMax = bbox.maxCorner().u[profileDesc.revolDim];
184  }
185 
186  if (hMax - hMin <= 0) {
187  if (m_app)
189  QString("Cloud is flat: can't generate a proper map!"),
191  } else {
192  hStepDoubleSpinBox->setMaximum(hMax - hMin);
193  }
194  }
195 
196  // add window
197  {
198  m_window = new ccMapWindow();
200  params.backgroundCol = ecvColor::white;
201  params.textDefaultCol = ecvColor::black;
202  params.drawBackgroundGradient = false;
203  params.colorScaleShowHistogram = false;
204  params.colorScaleRampWidth = 30;
205  params.decimateMeshOnMove = false;
206  params.displayCross = false;
207  params.colorScaleUseShader = false;
215 
216  m_window->showSF(displayColorScaleCheckBox->isChecked());
217  // add window to the right side layout
218  mapFrame->setLayout(new QHBoxLayout());
219 #ifdef CV_GL_WINDOW_USE_QWINDOW
220  mapFrame->layout()->addWidget(QWidget::createWindowContainer(m_window));
221 #else
222  mapFrame->layout()->addWidget(m_window);
223 #endif
224  precisionSpinBox->setValue(params.displayedNumPrecision);
225  }
226 
227  // create labels "clouds" (empty)
228  {
230  m_xLabels->showSymbols(false);
236  m_yLabels->showSymbols(false);
241  }
242 
243  connect(projectionComboBox, SIGNAL(currentIndexChanged(int)), this,
244  SLOT(projectionModeChanged(int)));
245  connect(angularUnitComboBox, SIGNAL(currentIndexChanged(int)), this,
246  SLOT(angularUnitChanged(int)));
247  connect(xStepDoubleSpinBox, SIGNAL(valueChanged(double)), this,
248  SLOT(updateGridSteps()));
249  connect(hStepDoubleSpinBox, SIGNAL(valueChanged(double)), this,
250  SLOT(updateGridSteps()));
251  connect(latStepDoubleSpinBox, SIGNAL(valueChanged(double)), this,
252  SLOT(updateGridSteps()));
253  connect(xMinDoubleSpinBox, SIGNAL(valueChanged(double)), this,
254  SLOT(updateGridSteps()));
255  connect(xMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this,
256  SLOT(updateGridSteps()));
257  connect(hMinDoubleSpinBox, SIGNAL(valueChanged(double)), this,
258  SLOT(updateGridSteps()));
259  connect(hMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this,
260  SLOT(updateGridSteps()));
261  connect(latMinDoubleSpinBox, SIGNAL(valueChanged(double)), this,
262  SLOT(updateGridSteps()));
263  connect(latMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this,
264  SLOT(updateGridSteps()));
265  connect(axisDimComboBox, SIGNAL(currentIndexChanged(int)), this,
266  SLOT(updateProfileRevolDim(int)));
267  connect(xOriginDoubleSpinBox, SIGNAL(valueChanged(double)), this,
268  SLOT(updateProfileOrigin()));
269  connect(yOriginDoubleSpinBox, SIGNAL(valueChanged(double)), this,
270  SLOT(updateProfileOrigin()));
271  connect(zOriginDoubleSpinBox, SIGNAL(valueChanged(double)), this,
272  SLOT(updateProfileOrigin()));
273  connect(baseRadiusDoubleSpinBox, SIGNAL(valueChanged(double)), this,
274  SLOT(baseRadiusChanged(double)));
275  connect(heightUnitLineEdit, SIGNAL(editingFinished()), this,
276  SLOT(updateHeightUnits()));
277  connect(exportCloudPushButton, SIGNAL(clicked()), this,
278  SLOT(exportMapAsCloud()));
279  connect(exportMeshPushButton, SIGNAL(clicked()), this,
280  SLOT(exportMapAsMesh()));
281  connect(exportMatrixPushButton, SIGNAL(clicked()), this,
282  SLOT(exportMapAsGrid()));
283  connect(exportImagePushButton, SIGNAL(clicked()), this,
284  SLOT(exportMapAsImage()));
285  connect(loadLabelsPushButton, SIGNAL(clicked()), this,
286  SLOT(loadOverlaySymbols()));
287  connect(clearLabelsPushButton, SIGNAL(clicked()), this,
288  SLOT(clearOverlaySymbols()));
289  connect(symbolSizeSpinBox, SIGNAL(valueChanged(int)), this,
290  SLOT(overlaySymbolsSizeChanged(int)));
291  connect(fontSizeSpinBox, SIGNAL(valueChanged(int)), this,
292  SLOT(labelFontSizeChanged(int)));
293  connect(precisionSpinBox, SIGNAL(valueChanged(int)), this,
294  SLOT(labelPrecisionChanged(int)));
295 
296  connect(colorScaleStepsSpinBox, SIGNAL(valueChanged(int)), this,
297  SLOT(colorRampStepsChanged(int)));
298  connect(overlayGridGroupBox, SIGNAL(toggled(bool)), this,
299  SLOT(toggleOverlayGrid(bool)));
300  connect(scaleXStepDoubleSpinBox, SIGNAL(editingFinished()), this,
301  SLOT(updateOverlayGrid()));
302  connect(scaleHStepDoubleSpinBox, SIGNAL(editingFinished()), this,
303  SLOT(updateOverlayGrid()));
304  connect(scaleLatStepDoubleSpinBox, SIGNAL(editingFinished()), this,
305  SLOT(updateOverlayGrid()));
306  connect(xScaleCheckBox, SIGNAL(clicked()), this, SLOT(updateOverlayGrid()));
307  connect(yScaleCheckBox, SIGNAL(clicked()), this, SLOT(updateOverlayGrid()));
308  connect(gridColorButton, SIGNAL(clicked()), this, SLOT(changeGridColor()));
309  connect(symbolColorButton, SIGNAL(clicked()), this,
310  SLOT(changeSymbolColor()));
311  connect(displayColorScaleCheckBox, SIGNAL(toggled(bool)), this,
312  SLOT(toggleColorScaleDisplay(bool)));
313  connect(updateVolumesPushButton, SIGNAL(clicked()), this,
314  SLOT(updateVolumes()));
315 
316  // DXF profiles export button is only visible/connected if DXF support is
317  // enabled!
319  connect(exportImageDXFButton, SIGNAL(clicked()), this,
320  SLOT(exportProfilesAsDXF()));
321  } else {
322  exportImageDXFButton->hide();
323  }
324 
325  // button box
326  {
327  QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply);
328  QPushButton* closeButton = buttonBox->button(QDialogButtonBox::Close);
329  connect(applyButton, SIGNAL(clicked()), this, SLOT(update()));
330  connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
331  }
332 
333  angularUnitChanged(m_angularUnits); // just to be sure
339 }
340 
342 
344  if (m_cloud && m_profile) {
347  profileDesc)) {
348  // compute mean 'radius'
349  // as well as min and max 'height'
350  double baseRadius = 0.0;
351  double minHeight = 0.0;
352  double maxHeight = 0.0;
353  for (unsigned i = 0; i < m_profile->size(); ++i) {
354  const CCVector3* P = m_profile->getPoint(i);
355  double radius = P->x;
356  double height = P->y + profileDesc.heightShift;
357  baseRadius += radius;
358 
359  if (i != 0) {
360  if (height < minHeight)
361  minHeight = height;
362  else if (height > maxHeight)
363  maxHeight = height;
364  } else {
365  minHeight = maxHeight = height;
366  }
367  }
368 
369  // set default 'base radius'
370  if (m_profile->size() != 0) baseRadius /= m_profile->size();
371  if (baseRadius == 0.0) baseRadius = 1.0;
372 
373  baseRadiusDoubleSpinBox->blockSignals(true);
374  baseRadiusDoubleSpinBox->setValue(baseRadius);
375  baseRadiusDoubleSpinBox->blockSignals(false);
376 
377  // set default min and max height
378  hMinDoubleSpinBox->blockSignals(true);
379  hMinDoubleSpinBox->setValue(minHeight);
380  hMinDoubleSpinBox->blockSignals(false);
381 
382  hMaxDoubleSpinBox->blockSignals(true);
383  hMaxDoubleSpinBox->setValue(maxHeight);
384  hMaxDoubleSpinBox->blockSignals(false);
385 
386  // do the same for the latitude
387 
388  // compute transformation from the cloud to the surface (of
389  // revolution)
390  ccGLMatrix cloudToSurfaceOrigin =
391  profileDesc.computeCloudToSurfaceOriginTrans();
392 
393  double minLat_rad = 0.0, maxLat_rad = 0.0;
395  m_cloud, minLat_rad, maxLat_rad, cloudToSurfaceOrigin,
396  static_cast<unsigned char>(profileDesc.revolDim))) {
397  latMinDoubleSpinBox->blockSignals(true);
398  latMinDoubleSpinBox->setValue(
399  ConvertAngleFromRad(minLat_rad, m_angularUnits));
400  latMinDoubleSpinBox->blockSignals(false);
401 
402  latMaxDoubleSpinBox->blockSignals(true);
403  latMaxDoubleSpinBox->setValue(
404  ConvertAngleFromRad(maxLat_rad, m_angularUnits));
405  latMaxDoubleSpinBox->blockSignals(false);
406  }
407  }
408  }
409 }
410 
412  // reset eveything, etc.
414 
415  clearView();
416 
417  // conical mode only
418  latLabel->setVisible(mode == PROJ_CONICAL);
419  latMinDoubleSpinBox->setVisible(mode == PROJ_CONICAL);
420  latMaxDoubleSpinBox->setVisible(mode == PROJ_CONICAL);
421  latStepDoubleSpinBox->setVisible(mode == PROJ_CONICAL);
422  latStepLabel->setVisible(mode == PROJ_CONICAL);
423  scaleLatStepLabel->setVisible(mode == PROJ_CONICAL);
424  scaleLatStepDoubleSpinBox->setVisible(mode == PROJ_CONICAL);
425  spanRatioFrame->setVisible(mode == PROJ_CONICAL);
426 
427  // cylindrical mode only
428  yLabel->setVisible(mode == PROJ_CYLINDRICAL);
429  hMinDoubleSpinBox->setVisible(mode == PROJ_CYLINDRICAL);
430  hMaxDoubleSpinBox->setVisible(mode == PROJ_CYLINDRICAL);
431  exportImageDXFButton->setVisible(mode == PROJ_CYLINDRICAL);
432  heightStepLabel->setVisible(mode == PROJ_CYLINDRICAL);
433  hStepDoubleSpinBox->setVisible(mode == PROJ_CYLINDRICAL);
434  scaleHeightStepLabel->setVisible(mode == PROJ_CYLINDRICAL);
435  scaleHStepDoubleSpinBox->setVisible(mode == PROJ_CYLINDRICAL);
436  heightUnitLineEdit->setVisible(mode == PROJ_CYLINDRICAL);
437  yScaleCheckBox->setVisible(mode == PROJ_CYLINDRICAL);
438 
440  updateGridSteps();
441 
442  if (m_map) update();
443 }
444 
447  switch (projectionComboBox->currentIndex()) {
448  case 0:
449  return PROJ_CYLINDRICAL;
450  case 1:
451  return PROJ_CONICAL;
452  default:
453  assert(false);
454  }
455 
456  return PROJ_CYLINDRICAL;
457 }
458 
461  switch (m_angularUnits) {
462  case 0: // degrees
463  return ANG_DEG;
464  case 1: // radians
465  return ANG_RAD;
466  case 2: // grades
467  return ANG_GRAD;
468  default:
469  assert(false);
470  }
471 
472  return ANG_DEG;
473 }
474 
476  switch (m_angularUnits) {
477  case 0: // degrees
478  return "deg";
479  case 1: // radians
480  return "rad";
481  case 2: // grades
482  return "grad";
483  default:
484  assert(false);
485  }
486 
487  return "none";
488 }
489 
491  switch (m_angularUnits) {
492  case 0: // degrees
493  return QChar(0x00B0);
494  case 1: // radians
495  return "rd";
496  case 2: // grades
497  return "gr";
498  default:
499  assert(false);
500  }
501 
502  return "none";
503 }
504 
506  QDoubleSpinBox* spinBox,
508  // no conversion necessary?
509  if (m_angularUnits == destUnit) return spinBox->value();
510 
511  // otherwise we convert to radians first
512  double angle_rad = ConvertAngleToRad(spinBox->value(), m_angularUnits);
513  // then to the destination value
514  return ConvertAngleFromRad(angle_rad, destUnit);
515 }
516 
518  if (!m_window || !box.isValid()) return;
519 
520  // we get the bounding-box diagonal length
521  PointCoordinateType bbDiag = box.getDiagNorm();
522  if (cloudViewer::GreaterThanEpsilon(bbDiag)) {
523  bool sfDisplayed =
525  bool yLabelDisplayed =
527  float centerPos = 0.5f;
528 
529  // we compute the pixel size (in world coordinates)
530  {
533  params.zoom = 1.0f;
534 
535  int screenWidth = ecvDisplayTools::GlWidth();
536  int scaleWidth = 0;
537  int labelsWidth = 0;
538  if (sfDisplayed) {
542  .horizontalAdvance("123.456789");
543  // scaleWidth =
544  // ecvDisplayTools::GetDisplayParameters().colorScaleRampWidth +
545  // QFontMetrics(ecvDisplayTools::GetTextDisplayFont()).width("123.456789");
546  }
547  if (yLabelDisplayed) {
548  // find the largest label width
549  QFont labelFont = ecvDisplayTools::GetTextDisplayFont();
550  labelFont.setPointSize(m_yLabels->getFontSize());
551  QFontMetrics fm(labelFont);
552  int maxWidth = 0;
553  for (unsigned i = 0; i < m_yLabels->size(); ++i) {
554  QString label = m_yLabels->getLabel(i);
555  if (!label.isNull()) {
556  // int width = fm.width(label);
557  int width = fm.horizontalAdvance(label);
558  maxWidth = std::max(maxWidth, width);
559  }
560  }
561  labelsWidth = maxWidth;
562  }
563 
564  // available room for the map
565  int mapWidth = std::max(1, screenWidth - scaleWidth - labelsWidth);
566 
567  // we zoom so that the map takes all the room left
568  float mapPart = static_cast<float>(mapWidth) /
569  static_cast<float>(screenWidth);
570  params.zoom *= mapPart;
571 
572  // we must also center the camera on the right position so that the
573  // map appears in between the scale and the color ramp
574  float mapStart = static_cast<float>(labelsWidth) /
575  static_cast<float>(screenWidth);
576  centerPos = (0.5f - mapStart) / mapPart;
577 
578  // update pixel size accordingly
579  float screenHeight =
580  ecvDisplayTools::GlHeight() * params.cameraAspectRatio;
581  params.pixelSize = static_cast<float>(
582  std::max(box.getDiagVec().x / mapWidth,
583  box.getDiagVec().y / screenHeight));
585  }
586 
587  // we set the pivot point on the box center
588  CCVector3 P = box.getCenter();
589  if (centerPos !=
590  0.5f) // if we don't look exactly at the center of the map
591  P.x = box.minCorner().x * (1.0f - centerPos) +
592  box.maxCorner().x * centerPos;
595 
599  }
600 
602 }
603 
605  if (!m_window) return;
606 
607  // remove existing sf
609 
610  // remove existing map (or maps?)
613  for (size_t i = 0; i < maps.size(); ++i) {
615  }
616 
617  // remove any polylines
618  {
619  ccHObject::Container polylines;
620  ecvDisplayTools::GetOwnDB()->filterChildren(polylines, false,
622  for (size_t i = 0; i < polylines.size(); ++i) {
623  ecvDisplayTools::RemoveFromOwnDB(polylines[i]);
624  }
625  }
626  m_xLabels->setVisible(false);
627  m_yLabels->setVisible(false);
628 }
629 
631  if (m_map) {
632  if (getProjectionMode() == PROJ_CONICAL) {
633  // we must check that the projection parameter have not changed!
634  // Otherwise the symbols will be misplaced...
635  double yMin, yMax, yStep;
636  getGridYValues(yMin, yMax, yStep, ANG_RAD);
637  if (!m_map->conical || m_map->yMin != yMin || m_map->yMax != yMax ||
638  m_map->conicalSpanRatio !=
639  conicSpanRatioDoubleSpinBox->value()) {
641  }
642  } else if (m_map->conical) {
643  // we can't keep the symbols when switching the projection mode
645  }
646  }
647 
648  // release memory
649  m_map.clear();
650 
651  // clear 3D view
652  clearView();
653 
654  // update map
655  m_map = updateMap();
656  // and GUI
657  exportGroupBox->setEnabled(m_map != 0);
658 
659  // auto update volumes
660  updateVolumes();
661 
662  if (m_map && m_window) {
663  ccMesh* mapMesh = 0;
664 
666  if (mode == PROJ_CYLINDRICAL) {
667  // by default we map an image on a plane
668  double dx = static_cast<double>(m_map->xSteps) * m_map->xStep;
669  double dy = static_cast<double>(m_map->ySteps) * m_map->yStep;
670  ccGLMatrix transMat;
671  transMat.setTranslation(CCVector3(
672  static_cast<PointCoordinateType>(dx / 2 + m_map->xMin),
673  static_cast<PointCoordinateType>(dy / 2 + m_map->yMin), 0));
674  ccPlane* mapPlane = new ccPlane(
675  static_cast<PointCoordinateType>(dx),
676  static_cast<PointCoordinateType>(dy), &transMat, "map");
677  mapMesh = static_cast<ccMesh*>(mapPlane);
678  } else // if (mode == PROJ_CONICAL) //conical projection
679  {
680  // no choice, we create a mesh
681  bool ccw = ccwCheckBox->isChecked();
682  m_map->conicalSpanRatio = conicSpanRatioDoubleSpinBox->value();
684  ccw);
685  }
686 
687  if (mapMesh) {
688  mapMesh->setVisible(true);
689  mapMesh->showNormals(false);
690  ecvDisplayTools::AddToOwnDB(mapMesh, false);
691 
693 
694  // add a virtual scalar field for color ramp display
695  ccScalarField* sf = new ccScalarField();
696  {
697  sf->reserve(2);
698  ScalarType smin = static_cast<ScalarType>(m_map->minVal);
699  ScalarType smax = static_cast<ScalarType>(m_map->maxVal);
700  sf->addElement(smin);
701  sf->addElement(smax);
702  sf->computeMinAndMax();
703  }
704  // selected color scale
705  ccColorScale::Shared colorScale =
708  colorScale = m_colorScaleSelector->getSelectedScale();
709  sf->setColorScale(colorScale);
710  sf->setColorRampSteps(colorScaleStepsSpinBox->value());
712  } else {
714  QString("Not enough memory to display the map!"),
716  }
717  }
718 
719  // update sf names, etc.
720  updateHeightUnits(); // already call 'updateOverlayGrid'!
721  // force grid update if necessary
722  // updateOverlayGrid();
723  // update zoom
724  ccBBox box =
725  m_window
727  : ccBBox();
728  updateZoom(box);
729 
731 }
732 
734  scaleHStepDoubleSpinBox->setSuffix(QString(" ") +
735  heightUnitLineEdit->text());
736 
739  QString("Distance (%1)").arg(getHeightUnitString())));
740  }
741 
743 }
744 
746  if (!m_map || !m_colorScaleSelector || !m_window) return;
747 
748  ccHObject::Container texturedEntities;
749 
751  if (mode == PROJ_CYLINDRICAL) {
752  // cylindrical projection: look for a plane
753  if (ecvDisplayTools::GetOwnDB()->filterChildren(texturedEntities, false,
754  CV_TYPES::PLANE) == 0)
755  return;
756  } else if (mode == PROJ_CONICAL) {
757  // conical projection: look for a standard mesh
758  if (ecvDisplayTools::GetOwnDB()->filterChildren(texturedEntities, false,
759  CV_TYPES::MESH) == 0)
760  return;
761  }
762 
763  // spawn "update" dialog
764  QProgressDialog progressDlg(QString("Updating..."), 0, 0, 0, 0, Qt::Popup);
765  progressDlg.setMinimumDuration(0);
766  progressDlg.setModal(true);
767  progressDlg.show();
768  QApplication::processEvents();
769 
770  // current color scale
772  if (!colorScale) {
773  if (m_app)
774  m_app->dispToConsole(QString("No color scale chosen!"),
776  return;
777  }
778 
779  // create new texture QImage
781  m_map, colorScale, colorScaleStepsSpinBox->value());
782  if (mapImage.isNull()) {
783  if (m_app)
785  QString("Failed to create map texture! Not enough memory?"),
787  return;
788  }
789 
790  for (size_t i = 0; i < texturedEntities.size(); ++i) {
791  // we release the old texture!
792  // texturedEntities[i]->setDisplay(0);
793  // texturedEntities[i]->setDisplay(m_window);
794 
795  // set new image as texture
796  if (mode == PROJ_CYLINDRICAL &&
797  texturedEntities[i]->isA(CV_TYPES::PLANE)) {
798  if (!static_cast<ccPlane*>(texturedEntities[i])
799  ->setAsTexture(mapImage)) {
800  if (m_app)
802  QString("Not enough memory to update the map!"),
804  return;
805  }
806  }
807  if (mode == PROJ_CONICAL && texturedEntities[i]->isA(CV_TYPES::MESH)) {
808  ccMesh* mesh = static_cast<ccMesh*>(texturedEntities[i]);
809  // set material
810  // ccMaterialSet* materialSet =
811  // const_cast<ccMaterialSet*>(mesh->getMaterialSet());
812  // assert(materialSet);
813  // remove old material (if any)
814  // materialSet->clear();
815  // add new material
816  //{
817  // ccMaterial::Shared material(new ccMaterial("texture"));
818  // material->setTexture(mapImage,QString(),false);
819  // materialSet->addMaterial(material);
820  // }
821  }
822  }
823 
825 }
826 
828  if (!m_window || !m_colorScaleSelector) return;
829 
831  if (sf) {
832  ccColorScale::Shared colorScale =
834  unsigned steps = static_cast<unsigned>(colorScaleStepsSpinBox->value());
835 
836  sf->setColorScale(colorScale);
837  sf->setColorRampSteps(steps);
838 
840  }
841 
842  // same thing with textures
844 }
845 
847  if (!m_app || !m_app->getColorScalesManager()) return;
848 
849  ccColorScale::Shared colorScale =
855  colorScale, m_app->getMainWindow());
856  if (cseDlg.exec()) {
857  colorScale = cseDlg.getActiveScale();
858  if (colorScale && m_colorScaleSelector) {
859  m_colorScaleSelector->init(); // in fact it's a 're-init'
860  m_colorScaleSelector->setSelectedScale(colorScale->getUuid());
861  }
862 
863  // save current scale manager state to persistent settings
865  }
866 }
867 
868 // helper
869 static void SetSpinBoxValues(QDoubleSpinBox* spinBox,
870  int decimals,
871  double minVal,
872  double maxVal,
873  double step,
874  double value) {
875  if (spinBox) {
876  spinBox->setDecimals(decimals);
877  spinBox->setRange(minVal, maxVal);
878  spinBox->setSingleStep(step);
879  spinBox->setValue(value);
880  }
881 }
882 
884  // backup previous value
885  double xStep_rad = getSpinboxAngularValue(xStepDoubleSpinBox, ANG_RAD);
886  double xMin_rad = getSpinboxAngularValue(xMinDoubleSpinBox, ANG_RAD);
887  double xMax_rad = getSpinboxAngularValue(xMaxDoubleSpinBox, ANG_RAD);
888  double scaleXStep_rad =
889  getSpinboxAngularValue(scaleXStepDoubleSpinBox, ANG_RAD);
890 
891  // same for latitude-related spinboxes
892  double latStep_rad = getSpinboxAngularValue(latStepDoubleSpinBox, ANG_RAD);
893  double latMin_rad = getSpinboxAngularValue(latMinDoubleSpinBox, ANG_RAD);
894  double latMax_rad = getSpinboxAngularValue(latMaxDoubleSpinBox, ANG_RAD);
895  double scaleLatStep_rad =
896  getSpinboxAngularValue(scaleLatStepDoubleSpinBox, ANG_RAD);
897 
898  switch (index) {
899  case 0: // degrees
900  {
902 
903  SetSpinBoxValues(xStepDoubleSpinBox, 2, 0.01, 360.0, 0.1,
904  cloudViewer::RadiansToDegrees(xStep_rad));
905  SetSpinBoxValues(scaleXStepDoubleSpinBox, 2, 0.01, 360.0, 5.0,
906  cloudViewer::RadiansToDegrees(scaleXStep_rad));
907  SetSpinBoxValues(xMinDoubleSpinBox, 2, 0.0, 360.0, 5.0,
909  SetSpinBoxValues(xMaxDoubleSpinBox, 2, 0.0, 360.0, 5.0,
911 
912  SetSpinBoxValues(latStepDoubleSpinBox, 2, 0.01, 89.99, 1.0,
913  cloudViewer::RadiansToDegrees(latStep_rad));
914  SetSpinBoxValues(scaleLatStepDoubleSpinBox, 2, 0.01, 89.99, 1.0,
915  cloudViewer::RadiansToDegrees(scaleLatStep_rad));
916  SetSpinBoxValues(latMinDoubleSpinBox, 2, -89.99, 89.99, 1.0,
917  cloudViewer::RadiansToDegrees(latMin_rad));
918  SetSpinBoxValues(latMaxDoubleSpinBox, 2, -89.99, 89.99, 1.0,
919  cloudViewer::RadiansToDegrees(latMax_rad));
920 
921  xMaxDoubleSpinBox->setMaximum(360.0);
922  xMaxDoubleSpinBox->setValue(360.0);
923  break;
924  }
925 
926  case 1: // radians
927  {
929 
930  double PIx2 = 2.0 * M_PI;
931  SetSpinBoxValues(xStepDoubleSpinBox, 4, 0.0001, PIx2, 0.1,
932  xStep_rad);
933  SetSpinBoxValues(scaleXStepDoubleSpinBox, 4, 0.0001, PIx2, 0.5,
934  scaleXStep_rad);
935  SetSpinBoxValues(xMinDoubleSpinBox, 4, 0.0, PIx2, 0.5, xMin_rad);
936  SetSpinBoxValues(xMaxDoubleSpinBox, 4, 0.0, PIx2, 0.5, xMax_rad);
937 
938  double PIdiv2 = M_PI / 2.0 - 0.0001;
939  SetSpinBoxValues(scaleLatStepDoubleSpinBox, 4, 0.0001, PIdiv2, 0.3,
940  scaleLatStep_rad);
941  SetSpinBoxValues(latStepDoubleSpinBox, 4, 0.0001, PIdiv2, 0.3,
942  latStep_rad);
943  SetSpinBoxValues(latMinDoubleSpinBox, 4, -PIdiv2, PIdiv2, 0.3,
944  latMin_rad);
945  SetSpinBoxValues(latMaxDoubleSpinBox, 4, -PIdiv2, PIdiv2, 0.3,
946  latMax_rad);
947 
948  xMaxDoubleSpinBox->setMaximum(PIx2);
949  xMaxDoubleSpinBox->setValue(PIx2);
950  break;
951  }
952 
953  case 2: // grades
954  {
956 
957  SetSpinBoxValues(xStepDoubleSpinBox, 2, 0.01, 400.0, 0.1,
958  xStep_rad * 200.0 / M_PI);
959  SetSpinBoxValues(scaleXStepDoubleSpinBox, 2, 0.01, 400.0, 5.0,
960  scaleXStep_rad * 200.0 / M_PI);
961  SetSpinBoxValues(xMinDoubleSpinBox, 2, 0.0, 400.0, 5.0,
962  xMin_rad * 200.0 / M_PI);
963  SetSpinBoxValues(xMaxDoubleSpinBox, 2, 0.0, 400.0, 5.0,
964  xMax_rad * 200.0 / M_PI);
965 
966  SetSpinBoxValues(scaleLatStepDoubleSpinBox, 2, 0.01, 99.99, 1.0,
967  scaleLatStep_rad * 200.0 / M_PI);
968  SetSpinBoxValues(latStepDoubleSpinBox, 2, 0.01, 99.99, 1.0,
969  latStep_rad * 200.0 / M_PI);
970  SetSpinBoxValues(latMinDoubleSpinBox, 2, -99.99, 99.99, 1.0,
971  latMin_rad * 200.0 / M_PI);
972  SetSpinBoxValues(latMaxDoubleSpinBox, 2, -99.99, 99.99, 1.0,
973  latMax_rad * 200.0 / M_PI);
974 
975  xMaxDoubleSpinBox->setMaximum(400.0);
976  xMaxDoubleSpinBox->setValue(400.0);
977  break;
978  }
979 
980  default: // shouldn't happen!
981  assert(false);
982  }
983 
984  // update spinboxes suffix
985  {
986  QString suffix = QString(" ") + getAngularUnitString();
987  scaleXStepDoubleSpinBox->setSuffix(suffix);
988  latMinDoubleSpinBox->setSuffix(suffix);
989  latMaxDoubleSpinBox->setSuffix(suffix);
990  scaleLatStepDoubleSpinBox->setSuffix(suffix);
991  }
992 
994 }
995 
997  double& minX,
998  double& maxX,
999  double& step,
1000  ANGULAR_UNIT unit /*=ANG_RAD*/) const {
1001  minX = getSpinboxAngularValue(xMinDoubleSpinBox, unit);
1002  maxX = getSpinboxAngularValue(xMaxDoubleSpinBox, unit);
1003  step = getSpinboxAngularValue(xStepDoubleSpinBox, unit);
1004 }
1005 
1007  double& minY,
1008  double& maxY,
1009  double& step,
1010  ANGULAR_UNIT unit /*=ANG_RAD*/) const {
1011  switch (getProjectionMode()) {
1012  case PROJ_CYLINDRICAL:
1013  minY = hMinDoubleSpinBox->value();
1014  maxY = hMaxDoubleSpinBox->value();
1015  step = hStepDoubleSpinBox->value();
1016  break;
1017  case PROJ_CONICAL:
1018  minY = getSpinboxAngularValue(latMinDoubleSpinBox, unit);
1019  maxY = getSpinboxAngularValue(latMaxDoubleSpinBox, unit);
1020  step = getSpinboxAngularValue(latStepDoubleSpinBox, unit);
1021  break;
1022  default:
1023  assert(false);
1024  break;
1025  }
1026 }
1027 
1029  ANGULAR_UNIT unit /*=ANG_RAD*/) const {
1031  return scaleHStepDoubleSpinBox->value();
1032  else
1033  return getSpinboxAngularValue(scaleLatStepDoubleSpinBox, unit);
1034 }
1035 
1037  if (!m_profile) {
1038  assert(false);
1039  return;
1040  }
1041 
1042  // update projection dimension
1043  assert(dim >= 0 && dim < 3);
1045 }
1046 
1048  if (!m_profile) {
1049  assert(false);
1050  return;
1051  }
1052 
1055 
1056  // update origin
1057  CCVector3 origin(
1058  static_cast<PointCoordinateType>(xOriginDoubleSpinBox->value()),
1059  static_cast<PointCoordinateType>(yOriginDoubleSpinBox->value()),
1060  static_cast<PointCoordinateType>(zOriginDoubleSpinBox->value()));
1061 
1062  // DGM: we must compensate for the change of shift along the revolution
1063  // axis!
1064  double dShift = origin.u[profileDesc.revolDim] -
1065  profileDesc.origin.u[profileDesc.revolDim];
1066  profileDesc.heightShift -= dShift;
1067 
1070  profileDesc.heightShift);
1071 
1072  if (dShift != 0) {
1073  clearOverlaySymbols(); // symbols placement depend on the origin
1074  // position along the revolution axis
1075  }
1077 }
1078 
1080  // angular step
1081  QString xStepsStr;
1082  {
1083  double minX, maxX, step;
1084  getGridXValues(minX, maxX, step, m_angularUnits);
1085  xStepsStr = (step > 0 ? QString::number(
1086  ceil(std::max(maxX - minX, 0.0) / step))
1087  : "inf");
1088  }
1089 
1090  // Y step
1091  QString yStepsStr;
1092  {
1093  double minY, maxY, step;
1094  getGridYValues(minY, maxY, step, m_angularUnits);
1095  yStepsStr = (step > 0 ? QString::number(
1096  ceil(std::max(maxY - minY, 0.0) / step))
1097  : "inf");
1098  }
1099 
1100  gridSizeLabel->setText(QString("%1 x %2").arg(xStepsStr).arg(yStepsStr));
1101 }
1102 
1104  return getProjectionMode() == PROJ_CONICAL
1105  ? 1.0
1106  : baseRadiusDoubleSpinBox->value();
1107 }
1108 
1110  if (!m_window) return;
1111 
1113  params.cameraAspectRatio = static_cast<float>(getBaseRadius());
1116 }
1117 
1119  return heightUnitLineEdit->text();
1120 }
1121 
1124  switch (fillingStrategyComboxBox->currentIndex()) {
1125  case 0:
1127  case 1:
1129  case 2:
1131  default:
1133  }
1135 }
1136 
1139  switch (emptyCellsComboBox->currentIndex()) {
1140  case 0:
1142  case 1:
1144  case 2:
1146  default:
1148  }
1150 }
1151 
1152 QSharedPointer<DistanceMapGenerationTool::Map>
1154  if (!m_cloud || !m_sf || !m_profile) {
1155  assert(false);
1156  return QSharedPointer<DistanceMapGenerationTool::Map>(0);
1157  }
1158 
1159  // profile parameters
1162  profileDesc)) {
1163  assert(false);
1164  return QSharedPointer<DistanceMapGenerationTool::Map>(0);
1165  }
1166 
1167  // compute transformation from cloud to the surface (of revolution)
1168  ccGLMatrix cloudToSurface = profileDesc.computeCloudToSurfaceOriginTrans();
1169 
1170  // steps
1171  double angStep_rad = getSpinboxAngularValue(xStepDoubleSpinBox, ANG_RAD);
1172  // CW (clockwise) or CCW (counterclockwise)
1173  bool ccw = ccwCheckBox->isChecked();
1174 
1175  // Y values
1176  double yMin, yMax, yStep;
1177  getGridYValues(yMin, yMax, yStep, ANG_RAD);
1178 
1179  // generate map
1181  m_cloud, m_sf, cloudToSurface, profileDesc.revolDim, angStep_rad,
1182  yStep, yMin, yMax, getProjectionMode() == PROJ_CONICAL, ccw,
1184 }
1185 
1187  if (!m_map) {
1188  if (m_app)
1189  m_app->dispToConsole(QString("Invalid map! Try to refresh it?"),
1191  return;
1192  }
1193  if (!m_profile) {
1194  if (m_app)
1195  m_app->dispToConsole(QString("Invalid profile?!"),
1197  return;
1198  }
1199 
1200  double baseRadius = getBaseRadius();
1201 
1203  m_map, m_profile, baseRadius);
1207  cloud->setName(
1208  m_cloud->getName() +
1209  QString(".map(%1,%2)").arg(m_map->xSteps).arg(m_map->ySteps));
1210 
1211  if (cloud && m_app) m_app->addToDB(cloud);
1212 }
1213 
1215  if (!m_profile || !m_colorScaleSelector) {
1216  assert(false);
1217  return;
1218  }
1219 
1220  if (!m_map) {
1221  if (m_app)
1222  m_app->dispToConsole(QString("Invalid map! Try to refresh it?"),
1224  return;
1225  }
1226 
1227  // profile parameters
1230  profileDesc)) {
1231  assert(false);
1232  return;
1233  }
1234 
1236 
1237  // create new texture QImage
1239  m_map, colorScale, colorScaleStepsSpinBox->value());
1240  if (mapImage.isNull()) {
1241  if (m_app)
1242  m_app->dispToConsole(QString("Failed to generate mesh texture! Not "
1243  "enough memory?"),
1245  return;
1246  }
1247 
1248  // compute transformation from cloud to the profile (origin)
1249  ccGLMatrix cloudToProfile = profileDesc.computeCloudToProfileOriginTrans();
1251  m_profile, cloudToProfile, m_map->counterclockwise, m_map->xSteps,
1252  mapImage);
1253 
1254  if (mesh) {
1255  // mesh->setDisplay_recursive(m_cloud->getDisplay());
1256  mesh->setName(
1257  m_cloud->getName() +
1258  QString(".map(%1,%2)").arg(m_map->xSteps).arg(m_map->ySteps));
1259  if (m_app) m_app->addToDB(mesh);
1260  } else {
1261  if (m_app)
1263  QString("Failed to generate mesh! Not enough memory?"),
1265  }
1266 }
1267 
1269  if (!m_map) {
1270  if (m_app)
1271  m_app->dispToConsole(QString("Invalid map! Try to refresh it?"),
1273  return;
1274  }
1275 
1276  // persistent settings (default export path)
1277  QSettings settings;
1278  settings.beginGroup("qSRA");
1279  QString path = settings.value("exportPath", ecvFileUtils::defaultDocPath())
1280  .toString();
1281 
1282  QString filter("Grid file (*.csv)");
1283 
1284  // open file saving dialog
1285  QString filename =
1286  QFileDialog::getSaveFileName(0, "Select output file", path, filter);
1287  if (filename.isEmpty()) return;
1288 
1289  // save current export path to persistent settings
1290  settings.setValue("exportPath", QFileInfo(filename).absolutePath());
1291 
1292  QString xUnit = getAngularUnitString();
1293  double xConversionFactor = ConvertAngleFromRad(1.0, m_angularUnits);
1294  QString yUnit = getHeightUnitString();
1295  double yConversionFactor = 1.0;
1296 
1298  m_map, filename, xUnit, yUnit, xConversionFactor,
1299  yConversionFactor, m_app)) {
1300  if (m_app)
1302  QString("File '%1' saved successfully").arg(filename),
1304  }
1305 }
1306 
1308  if (!m_window) return;
1309 
1312  m_app->getMainWindow());
1313  rtfDlg.hideOptions();
1314 
1315  if (rtfDlg.exec()) {
1316  QApplication::processEvents();
1318  rtfDlg.dontScalePoints(),
1319  rtfDlg.renderOverlayItems());
1320  }
1321 }
1322 
1324  if (!m_map || !m_profile) return;
1325 
1326  DxfProfilesExportDlg dpeDlg(this);
1327 
1328  if (!dpeDlg.exec()) return;
1329 
1330  // profile meta-data (we only need the height shift)
1331  PointCoordinateType heightShift = 0;
1333 
1335  params.legendTheoProfileTitle = dpeDlg.theoNameLineEdit->text();
1336  params.legendRealProfileTitle = dpeDlg.realNameLineEdit->text();
1337  params.scaledDevUnits = dpeDlg.scaledDevUnitsLineEdit->text();
1338  params.devLabelMultCoef = dpeDlg.devValuesScaleDoubleSpinBox->value();
1339  params.devMagnifyCoef = dpeDlg.magnifyCoefSpinBox->value();
1340  params.precision = dpeDlg.precisionSpinBox->value();
1341 
1342  /*** vertical profiles ***/
1343 
1344  int angularStepCount = dpeDlg.angularStepsSpinBox->value();
1345  assert(angularStepCount >= 1);
1346  // we take the same steps as the overlay grid for labels
1347  QString vertFilename = dpeDlg.getVertFilename();
1348  if (!vertFilename.isNull()) {
1349  // generate profiles titles
1350  params.profileTitles.clear();
1351  QString vertProfileBaseTitle = dpeDlg.vertTitleLineEdit->text();
1352  for (int i = 0; i < angularStepCount; ++i) {
1353  double angle_rad =
1354  static_cast<double>(i) * 2.0 * M_PI / angularStepCount;
1355  double angle_cur = ConvertAngleFromRad(angle_rad, m_angularUnits);
1356  params.profileTitles << QString("%1 - %2 %3")
1357  .arg(vertProfileBaseTitle)
1358  .arg(angle_cur)
1359  .arg(getAngularUnitString());
1360  }
1361 
1362  double heightStep = getScaleYStep();
1364  m_map, m_profile, vertFilename, angularStepCount,
1365  heightStep, heightShift, params, m_app)) {
1366  if (m_app)
1368  QString("Failed to save file '%1'!").arg(vertFilename),
1370  return;
1371  } else {
1372  if (m_app)
1373  m_app->dispToConsole(QString("File '%1' saved successfully")
1374  .arg(vertFilename),
1376  }
1377  }
1378 
1379  /*** horizontal profiles ***/
1380 
1381  QString horizFilename = dpeDlg.getHorizFilename();
1382  int heightStepCount = dpeDlg.heightStepsSpinBox->value();
1383  assert(heightStepCount >= 1);
1384  // we take the same steps as the overlay grid for labels
1385  if (!horizFilename.isNull()) {
1386  // generate profiles titles
1387  params.profileTitles.clear();
1388  QString horizProfileBaseTitle = dpeDlg.horizTitleLineEdit->text();
1389  params.profileTitles
1390  << QString("%1 - %2 ").arg(horizProfileBaseTitle).arg("%1") +
1392 
1393  double angleStep_rad =
1394  getSpinboxAngularValue(scaleXStepDoubleSpinBox, ANG_RAD);
1396  m_map, m_profile, horizFilename, heightStepCount,
1397  heightShift, angleStep_rad,
1400  if (m_app)
1402  QString("Failed to save file '%1'!").arg(horizFilename),
1404  return;
1405  } else {
1406  if (m_app)
1407  m_app->dispToConsole(QString("File '%1' saved successfully")
1408  .arg(horizFilename),
1410  }
1411  }
1412 }
1413 
1415  // need a valid map
1416  if (!m_map) {
1417  if (m_app)
1418  m_app->dispToConsole(QString("Generate a valid map first!"),
1420  return;
1421  }
1422 
1423  // profile parameters
1426  profileDesc)) {
1427  assert(false);
1428  return;
1429  }
1430 
1431  // persistent settings (default import path)
1432  QSettings settings;
1433  settings.beginGroup("qSRA");
1434  QString path = settings.value("importPath", ecvFileUtils::defaultDocPath())
1435  .toString();
1436 
1437  QString filter("Symbols (*.txt)");
1438 
1439  // open file loading dialog
1440  QString filename = QFileDialog::getOpenFileName(0, "Select symbols file",
1441  path, filter);
1442  if (filename.isEmpty()) return;
1443 
1444  QFileInfo fileInfo(filename);
1445  if (!fileInfo.exists()) //?!
1446  {
1447  if (m_app)
1449  QString("Failed to find symbol file '%1'?!").arg(filename),
1451  return;
1452  }
1453 
1454  // save current impoort path to persistent settings
1455  settings.setValue("importPath", fileInfo.absolutePath());
1456 
1457  ccSymbolCloud* symbolCloud = 0;
1458  // try to load the file (as a "symbol" point cloud)
1459  {
1460  QFile file(filename);
1461  assert(file.exists());
1462  if (!file.open(QFile::ReadOnly)) {
1463  if (m_app)
1464  m_app->dispToConsole(QString("Failed to open symbol file '%1'!")
1465  .arg(filename),
1467  return;
1468  }
1469 
1470  symbolCloud = new ccSymbolCloud(fileInfo.baseName());
1471 
1472  QTextStream stream(&file);
1473  QString currentLine = stream.readLine();
1474  bool error = false;
1475  while (!currentLine.isNull()) {
1476  QStringList tokens = qtCompatSplitRegex(currentLine, "\\s+",
1478  if (tokens.size() == 4) {
1479  bool okX, okY, okZ;
1480  CCVector3 P(static_cast<PointCoordinateType>(
1481  tokens[1].toDouble(&okX)),
1482  static_cast<PointCoordinateType>(
1483  tokens[2].toDouble(&okY)),
1484  static_cast<PointCoordinateType>(
1485  tokens[3].toDouble(&okZ)));
1486 
1487  if (!okX || !okY || !okZ) {
1488  error = true;
1489  break;
1490  }
1491 
1492  QString label = tokens[0];
1493  if (symbolCloud->size() == symbolCloud->capacity()) {
1494  if (!symbolCloud->reserveThePointsTable(
1495  symbolCloud->size() + 64) ||
1496  !symbolCloud->reserveLabelArray(symbolCloud->size() +
1497  64)) {
1498  if (m_app)
1500  QString("Not enough memory!"),
1502  error = true;
1503  break;
1504  }
1505  }
1506 
1507  // DGM: warning, for historical reasons height values are
1508  // expressed relative to the profile origin!
1509  P.u[profileDesc.revolDim] +=
1510  profileDesc.origin.u[profileDesc.revolDim];
1511 
1512  symbolCloud->addPoint(P);
1513  symbolCloud->addLabel(label);
1514  }
1515 
1516  // next line
1517  currentLine = stream.readLine();
1518  }
1519 
1520  if (symbolCloud->size() == 0) {
1521  delete symbolCloud;
1522  symbolCloud = 0;
1523  } else {
1524  symbolCloud->shrinkToFit();
1525  }
1526 
1527  if (error) {
1528  delete symbolCloud;
1529  symbolCloud = nullptr;
1530 
1531  if (m_app)
1533  QString("An error occurred while loading the file! "
1534  "Result may be incomplete"),
1536  return;
1537  }
1538  }
1539 
1540  if (symbolCloud) {
1541  // unroll the symbol cloud the same way as the input cloud
1542  if (m_window) {
1543  // compute transformation from cloud to the surface (of revolution)
1544  ccGLMatrix cloudToSurface =
1545  profileDesc.computeCloudToSurfaceOriginTrans();
1546  // CW (clockwise) or CCW (counterclockwise)
1547  bool ccw = ccwCheckBox->isChecked();
1548 
1551  symbolCloud, cloudToSurface, profileDesc.revolDim, ccw);
1552  } else /*if (getProjectionMode() == PROJ_CONICAL)*/
1553  {
1554  double conicalSpanRatio = conicSpanRatioDoubleSpinBox->value();
1556  symbolCloud, cloudToSurface, profileDesc.revolDim,
1557  m_map->yMin, m_map->yMax, conicalSpanRatio, ccw);
1558  }
1559  }
1560  symbolCloud->setSymbolSize(
1561  static_cast<double>(symbolSizeSpinBox->value()));
1562  symbolCloud->setFontSize(fontSizeSpinBox->value());
1563  symbolCloud->setVisible(true);
1564  // symbolCloud->setDisplay(m_window);
1565  ecvColor::Rgb rgb(static_cast<ColorCompType>(m_symbolColor.red()),
1566  static_cast<ColorCompType>(m_symbolColor.green()),
1567  static_cast<ColorCompType>(m_symbolColor.blue()));
1568  symbolCloud->setTempColor(rgb, true);
1569  if (m_window != nullptr) {
1570  ecvDisplayTools::AddToOwnDB(symbolCloud, false);
1572  }
1573 
1574  clearLabelsPushButton->setEnabled(true);
1575  clearLabelsPushButton->setText(
1576  QString("Clear (%1)").arg(symbolCloud->size()));
1577  } else {
1578  assert(false);
1579  delete symbolCloud;
1580  symbolCloud = 0;
1581  }
1582 }
1583 
1585  if (!m_window) return;
1586 
1587  ccHObject::Container clouds;
1588  ecvDisplayTools::GetOwnDB()->filterChildren(clouds, false,
1590 
1591  for (size_t i = 0; i < clouds.size(); ++i)
1592  if (clouds[i] != m_xLabels && clouds[i] != m_yLabels)
1594 
1595  clearLabelsPushButton->setEnabled(false);
1596  clearLabelsPushButton->setText("Clear");
1598 }
1599 
1601  if (!m_window) return;
1602 
1603  double symbolSize = (double)symbolSizeSpinBox->value();
1604 
1606  for (unsigned i = 0; i < db->getChildrenNumber(); ++i) {
1607  ccHObject* child = db->getChild(i);
1608  if (child->isA(CV_TYPES::POINT_CLOUD) && child != m_xLabels &&
1609  child != m_yLabels) // don't modify the X an Y label clouds!
1610  {
1611  static_cast<ccSymbolCloud*>(child)->setSymbolSize(symbolSize);
1612  }
1613  }
1615 }
1616 
1618  ccQtHelpers::SetButtonColor(symbolColorButton, m_symbolColor);
1619 
1620  if (!m_window) return;
1621 
1622  ecvColor::Rgb rgb(static_cast<ColorCompType>(m_symbolColor.red()),
1623  static_cast<ColorCompType>(m_symbolColor.green()),
1624  static_cast<ColorCompType>(m_symbolColor.blue()));
1625 
1627  for (unsigned i = 0; i < db->getChildrenNumber(); ++i) {
1628  ccHObject* child = db->getChild(i);
1629  if (child->isA(CV_TYPES::POINT_CLOUD) && child != m_xLabels &&
1630  child != m_yLabels) // don't modify the X an Y label clouds!
1631  {
1632  child->setTempColor(rgb, true);
1633  }
1634  }
1635 
1637 }
1638 
1640  ccQtHelpers::SetButtonColor(gridColorButton, m_gridColor);
1641 
1642  if (!m_window) return;
1643 
1644  ecvColor::Rgb rgb(static_cast<ColorCompType>(m_gridColor.red()),
1645  static_cast<ColorCompType>(m_gridColor.green()),
1646  static_cast<ColorCompType>(m_gridColor.blue()));
1647 
1649  for (unsigned i = 0; i < db->getChildrenNumber(); ++i) {
1650  ccHObject* child = db->getChild(i);
1651  if (child->isA(CV_TYPES::POLY_LINE)) {
1652  static_cast<ccPolyline*>(child)->setColor(rgb);
1653  }
1654  }
1655 
1656  m_xLabels->setTempColor(rgb, true);
1657  m_yLabels->setTempColor(rgb, true);
1658 
1660 }
1661 
1663  if (!m_window) return;
1664 
1665  int fontSize = fontSizeSpinBox->value();
1666 
1668  for (unsigned i = 0; i < db->getChildrenNumber(); ++i) {
1669  ccHObject* child = db->getChild(i);
1670  if (child->isA(CV_TYPES::POINT_CLOUD)) {
1671  static_cast<ccSymbolCloud*>(child)->setFontSize(fontSize);
1672  }
1673  }
1674 
1675  // update window font-size
1677  params.defaultFontSize = fontSize;
1678 
1681 }
1682 
1684  if (!m_window) return;
1685 
1686  // update numerical precision
1688  params.displayedNumPrecision = prec;
1690 
1692 }
1693 
1695  colorScaleChanged(-1); // dummy index, not used
1696 }
1697 
1699  toggleOverlayGrid(overlayGridGroupBox->isChecked());
1700 }
1701 
1703  if (!m_window) return;
1704 
1705  assert(m_xLabels && m_yLabels);
1706  if (!m_xLabels || !m_yLabels) return;
1707 
1708  // remove any polylines
1709  {
1710  ccHObject::Container polylines;
1711  ecvDisplayTools::GetOwnDB()->filterChildren(polylines, false,
1713  for (size_t i = 0; i < polylines.size(); ++i)
1714  ecvDisplayTools::RemoveFromOwnDB(polylines[i]);
1715  }
1716  // and labels
1717  m_xLabels->clear();
1718  m_yLabels->clear();
1719  m_xLabels->setVisible(state && xScaleCheckBox->isChecked());
1720  m_yLabels->setVisible(state && yScaleCheckBox->isChecked());
1721 
1722  if (state && m_map) // on
1723  {
1724  ecvColor::Rgb rgb(static_cast<ColorCompType>(m_gridColor.red()),
1725  static_cast<ColorCompType>(m_gridColor.green()),
1726  static_cast<ColorCompType>(m_gridColor.blue()));
1727 
1728  // we reconstruct the grid and the corresponding labels
1729  double xMin_rad, xMax_rad, xStep_rad;
1730  getGridXValues(xMin_rad, xMax_rad, xStep_rad, ANG_RAD);
1731  double scaleXStep_rad =
1732  getSpinboxAngularValue(scaleXStepDoubleSpinBox, ANG_RAD);
1733 
1734  double yMin, yMax, yStep;
1735  getGridYValues(yMin, yMax, yStep, ANG_RAD);
1736  double scaleYStep = getScaleYStep(ANG_RAD);
1737 
1738  if (scaleXStep_rad == 0 || scaleYStep == 0) {
1739  if (m_app)
1741  QString("Internal error: invalid step values?!"),
1744  return;
1745  }
1746 
1747  unsigned xStepCount = static_cast<unsigned>(
1748  ceil(std::max(xMax_rad - xMin_rad, 0.0) / scaleXStep_rad));
1749  unsigned yStepCount = static_cast<unsigned>(
1750  ceil(std::max(yMax - yMin, 0.0) / scaleYStep));
1751 
1752  // correct 'xMax' and 'yMax'
1753  xMax_rad = xMin_rad + static_cast<double>(xStepCount) * scaleXStep_rad;
1754  yMax = yMin + static_cast<double>(yStepCount) * scaleYStep;
1755 
1756  // projection mode
1758  double nProj = 1.0;
1759  if (mode == PROJ_CONICAL) {
1760  double conicalSpanRatio = conicSpanRatioDoubleSpinBox->value();
1762  m_map->yMax) *
1763  conicalSpanRatio;
1764  }
1765  bool ccw = ccwCheckBox->isChecked();
1766 
1767  // create vertical polylines
1768  {
1769  QString angularUnitsStr = getCondensedAngularUnitString();
1770  if (m_xLabels->isVisible()) {
1771  if (!m_xLabels->reserve(xStepCount + 1) ||
1772  !m_xLabels->reserveLabelArray(xStepCount + 1)) {
1773  if (m_app)
1775  QString("Not engouh memory to display the 'X' "
1776  "scale?!"),
1778  m_xLabels->clear();
1779  m_xLabels->setVisible(false);
1780  }
1781  m_xLabels->setTempColor(rgb, true);
1782  }
1783  for (unsigned i = 0; i <= xStepCount; ++i) {
1784  double angle_rad =
1785  xMin_rad + static_cast<double>(i) * scaleXStep_rad;
1786 
1787  CCVector3 Pbottom(static_cast<PointCoordinateType>(angle_rad),
1788  static_cast<PointCoordinateType>(yMin), 0);
1789  CCVector3 Pup(static_cast<PointCoordinateType>(angle_rad),
1790  static_cast<PointCoordinateType>(yMax), 0);
1791 
1792  if (mode == PROJ_CONICAL) {
1793  // vertical lines remain "straight" lines after Conical
1794  // projection
1796  Pbottom.x, Pbottom.y, m_map->yMin, nProj, ccw);
1798  Pup.x, Pup.y, m_map->yMin, nProj, ccw);
1799  }
1800  Pbottom.z = 1.0;
1801  Pup.z = 1.0;
1802 
1803  // polyline
1804  ccPointCloud* vertices = new ccPointCloud(/*QString("Angle %1").arg(static_cast<int>(cloudViewer::RadiansToDegrees(angle_rad)))*/);
1805  vertices->reserve(2);
1806  vertices->addPoint(Pbottom);
1807  vertices->addPoint(Pup);
1808  ccPolyline* poly = new ccPolyline(vertices);
1809  poly->addPointIndex(0, 2);
1810  poly->addChild(vertices);
1811  vertices->setEnabled(false);
1812  poly->setColor(rgb);
1813  poly->showColors(true);
1814  poly->setVisible(true);
1815  poly->set2DMode(false);
1816  ecvDisplayTools::AddToOwnDB(poly, false);
1817 
1818  if (m_xLabels->isVisible()) {
1819  m_xLabels->addPoint(Pbottom);
1821  QString("%1%2")
1822  .arg(ConvertAngleFromRad(angle_rad,
1823  m_angularUnits),
1824  0, 'f',
1825  m_angularUnits == ANG_RAD ? 2 : 0)
1826  .arg(angularUnitsStr));
1827  }
1828  }
1829  }
1830 
1831  // create horizontal polylines
1832  {
1833  if (m_yLabels->isVisible()) {
1834  if (!m_yLabels->reserve(yStepCount + 1) ||
1835  !m_yLabels->reserveLabelArray(yStepCount + 1)) {
1836  if (m_app)
1838  QString("Not enough memory to display the 'Y' "
1839  "scale?!"),
1841  m_yLabels->clear();
1842  m_yLabels->setVisible(false);
1843  }
1844  m_yLabels->setTempColor(rgb, true);
1845  }
1846  for (unsigned i = 0; i <= yStepCount; ++i) {
1847  double y = yMin + static_cast<double>(i) * scaleYStep;
1848 
1849  // polyline
1850  ccPointCloud* vertices =
1851  new ccPointCloud(/*QString("Height %1").arg(height)*/);
1852 
1853  if (mode == PROJ_CONICAL) {
1854  // horizontal lines become "curved" lines after Conical
1855  // projection!
1856  const unsigned polySteps = 100;
1857  if (vertices->reserve(polySteps + 1))
1858  for (unsigned j = 0; j <= polySteps; ++j) {
1859  double angle_rad =
1860  xMin_rad +
1861  static_cast<double>(j) /
1862  static_cast<double>(polySteps) *
1863  (xMax_rad - xMin_rad);
1865  ProjectPointOnCone(angle_rad, y,
1866  m_map->yMin, nProj, ccw);
1867  P.z = 1.0;
1868  vertices->addPoint(P);
1869  }
1870  } else {
1871  CCVector3 Pleft(static_cast<PointCoordinateType>(xMin_rad),
1872  static_cast<PointCoordinateType>(y),
1873  PC_ONE);
1874  CCVector3 Pright(static_cast<PointCoordinateType>(xMax_rad),
1875  static_cast<PointCoordinateType>(y),
1876  PC_ONE);
1877  vertices->reserve(2);
1878  vertices->addPoint(Pleft);
1879  vertices->addPoint(Pright);
1880  }
1881 
1882  unsigned vertCount = vertices->size();
1883  if (vertCount) {
1884  ccPolyline* poly = new ccPolyline(vertices);
1885  poly->addPointIndex(0, vertices->size());
1886  poly->addChild(vertices);
1887  vertices->setEnabled(false);
1888  poly->setColor(rgb);
1889  poly->showColors(true);
1890  poly->setVisible(true);
1891  poly->set2DMode(false);
1892  ecvDisplayTools::AddToOwnDB(poly, false);
1893  } else {
1894  delete vertices;
1895  vertices = 0;
1896  }
1897 
1898  if (mode != PROJ_CONICAL && m_yLabels->isVisible()) {
1899  // cylindrical 'mode' labels
1900  CCVector3 Pleft(static_cast<PointCoordinateType>(xMin_rad),
1901  static_cast<PointCoordinateType>(y),
1902  PC_ONE);
1903  m_yLabels->addPoint(Pleft);
1905  QString("%1 %2").arg(y).arg(getHeightUnitString()));
1906  }
1907  }
1908  }
1909  }
1910 
1912 }
1913 
1915  QColor newCol = QColorDialog::getColor(m_gridColor, this);
1916  if (!newCol.isValid()) return;
1917 
1918  m_gridColor = newCol;
1919 
1921 }
1922 
1924  QColor newCol = QColorDialog::getColor(m_symbolColor, this);
1925  if (!newCol.isValid()) return;
1926 
1927  m_symbolColor = newCol;
1928 
1930 }
1931 
1933  if (m_window) {
1934  m_window->showSF(state);
1936  }
1937 }
1938 
1940  if (getProjectionMode() == PROJ_CONICAL) {
1941  volumeTextEdit->setText("Cylindrical projection mode only!");
1942  return;
1943  }
1944 
1945  if (m_map && m_profile) {
1949  m_map, m_profile, surfaces, volumes)) {
1950  QLocale locale(QLocale::English);
1951  QString text;
1952  text.append(QString("[Theoretical]\n"));
1953  text.append(QString("surface = %1\n")
1954  .arg(locale.toString(surfaces.theoretical)));
1955  text.append(QString("volume = %1\n")
1956  .arg(locale.toString(volumes.theoretical)));
1957  text.append(QString("\n"));
1958  text.append(QString("[Actual]\n"));
1959  text.append(QString("Surface: %1\n")
1960  .arg(locale.toString(surfaces.total)));
1961  text.append(QString("Volume: %1\n")
1962  .arg(locale.toString(volumes.total)));
1963  text.append(QString("\n"));
1964  text.append(QString("Positive (deviations) surface:\n%1\n")
1965  .arg(locale.toString(surfaces.positive)));
1966  text.append(QString("Negative (deviations) surface:\n%1\n")
1967  .arg(locale.toString(surfaces.negative)));
1968  text.append(QString("\n"));
1969  text.append(QString("Positive volume (gain of matter):\n%1\n")
1970  .arg(locale.toString(volumes.positive)));
1971  text.append(QString("Negative volume (loss of matter):\n%1\n")
1972  .arg(locale.toString(volumes.negative)));
1973  text.append(QString("Sum:\n%1\n")
1974  .arg(locale.toString(volumes.positive +
1975  volumes.negative)));
1976  volumeTextEdit->setText(text);
1977  } else {
1978  volumeTextEdit->setText("Volume(s) computation failed!");
1979  }
1980  } else {
1981  if (!m_map)
1982  volumeTextEdit->setText("No map!");
1983  else
1984  volumeTextEdit->setText("No profile defined!");
1985  }
1986 }
1987 
1989  QSettings settings;
1990  settings.beginGroup("DistanceMapGenerationDialog");
1991 
1992  // read parameters
1993  double conicSpanRatio = settings.value("conicSpanRatio",
1994  conicSpanRatioDoubleSpinBox->value())
1995  .toDouble();
1996  int angularUnit =
1997  settings.value("angularUnit", angularUnitComboBox->currentIndex())
1998  .toInt();
1999  QString heightUnit =
2000  settings.value("heightUnit", heightUnitLineEdit->text()).toString();
2001  double angularStep =
2002  settings.value("angularStep", xStepDoubleSpinBox->value())
2003  .toDouble();
2004  double heightStep =
2005  settings.value("heightStep", hStepDoubleSpinBox->value())
2006  .toDouble();
2007  double latitudeStep =
2008  settings.value("latitudeStep", latStepDoubleSpinBox->value())
2009  .toDouble();
2010  double scaleAngularStep =
2011  settings.value("scaleAngularStep", scaleXStepDoubleSpinBox->value())
2012  .toDouble();
2013  double scaleHeightStep =
2014  settings.value("scaleHeightStep", scaleHStepDoubleSpinBox->value())
2015  .toDouble();
2016  double scaleLatitudeStep =
2017  settings.value("scaleLatitudeStep",
2018  scaleLatStepDoubleSpinBox->value())
2019  .toDouble();
2020  bool ccw = settings.value("CCW", ccwCheckBox->isChecked()).toBool();
2021  int fillStrategy = settings.value("fillStrategy",
2022  fillingStrategyComboxBox->currentIndex())
2023  .toBool();
2024  int emptyCells =
2025  settings.value("emptyCells", emptyCellsComboBox->currentIndex())
2026  .toInt();
2027  bool showOverlayGrid =
2028  settings.value("showOverlayGrid", overlayGridGroupBox->isChecked())
2029  .toBool();
2030  bool showXScale =
2031  settings.value("showXScale", xScaleCheckBox->isChecked()).toBool();
2032  bool showYScale =
2033  settings.value("showYScale", yScaleCheckBox->isChecked()).toBool();
2034  bool showColorScale = settings.value("showColorScale",
2035  displayColorScaleCheckBox->isChecked())
2036  .toBool();
2037  QString uuid = settings.value("colorScale", QString()).toString();
2038  int colorScaleSteps =
2039  settings.value("colorScaleSteps", colorScaleStepsSpinBox->value())
2040  .toInt();
2041  int symbolSize =
2042  settings.value("symbolSize", symbolSizeSpinBox->value()).toInt();
2043  int fontSize = settings.value("fontSize", fontSizeSpinBox->value()).toInt();
2044 
2045  // apply parameters
2046  conicSpanRatioDoubleSpinBox->setValue(conicSpanRatio);
2047  angularUnitComboBox->setCurrentIndex(angularUnit);
2048  angularUnitChanged(angularUnit); // force update
2049  heightUnitLineEdit->setText(heightUnit);
2050  updateHeightUnits(); // force update
2051  xStepDoubleSpinBox->setValue(angularStep);
2052  hStepDoubleSpinBox->setValue(heightStep);
2053  latStepDoubleSpinBox->setValue(latitudeStep);
2054  scaleXStepDoubleSpinBox->setValue(scaleAngularStep);
2055  scaleHStepDoubleSpinBox->setValue(scaleHeightStep);
2056  scaleLatStepDoubleSpinBox->setValue(scaleLatitudeStep);
2057  ccwCheckBox->setChecked(ccw);
2058  fillingStrategyComboxBox->setCurrentIndex(fillStrategy);
2059  emptyCellsComboBox->setCurrentIndex(emptyCells);
2060  overlayGridGroupBox->setChecked(showOverlayGrid);
2061  xScaleCheckBox->setChecked(showXScale);
2062  yScaleCheckBox->setChecked(showYScale);
2063  displayColorScaleCheckBox->setChecked(showColorScale);
2064  if (m_colorScaleSelector && !uuid.isNull())
2066  colorScaleStepsSpinBox->setValue(colorScaleSteps);
2067  symbolSizeSpinBox->setValue(symbolSize);
2068  fontSizeSpinBox->setValue(fontSize);
2069 
2070  settings.endGroup();
2071 }
2072 
2074  QSettings settings;
2075  settings.beginGroup("DistanceMapGenerationDialog");
2076 
2077  // write parameters
2078  settings.setValue("conicSpanRatio", conicSpanRatioDoubleSpinBox->value());
2079  settings.setValue("angularUnit", angularUnitComboBox->currentIndex());
2080  settings.setValue("heightUnit", heightUnitLineEdit->text());
2081  settings.setValue("angularStep", xStepDoubleSpinBox->value());
2082  settings.setValue("heightStep", hStepDoubleSpinBox->value());
2083  settings.setValue("latitudeStep", latStepDoubleSpinBox->value());
2084  settings.setValue("scaleAngularStep", scaleXStepDoubleSpinBox->value());
2085  settings.setValue("scaleHeightStep", scaleHStepDoubleSpinBox->value());
2086  settings.setValue("scaleLatitudeStep", scaleLatStepDoubleSpinBox->value());
2087  settings.setValue("CCW", ccwCheckBox->isChecked());
2088  settings.setValue("fillStrategy", fillingStrategyComboxBox->currentIndex());
2089  settings.setValue("emptyCells", emptyCellsComboBox->currentIndex());
2090  settings.setValue("showOverlayGrid", overlayGridGroupBox->isChecked());
2091  settings.setValue("showXScale", xScaleCheckBox->isChecked());
2092  settings.setValue("showYScale", yScaleCheckBox->isChecked());
2093  settings.setValue("showColorScale", displayColorScaleCheckBox->isChecked());
2094  if (m_colorScaleSelector) {
2095  ccColorScale::Shared colorScale =
2097  if (colorScale) settings.setValue("colorScale", colorScale->getUuid());
2098  }
2099  settings.setValue("colorScaleSteps", colorScaleStepsSpinBox->value());
2100  settings.setValue("symbolSize", symbolSizeSpinBox->value());
2101  settings.setValue("fontSize", fontSizeSpinBox->value());
2102 
2103  settings.endGroup();
2104 }
constexpr PointCoordinateType PC_ONE
'1' as a PointCoordinateType value
Definition: CVConst.h:67
constexpr double M_PI
Pi.
Definition: CVConst.h:19
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
std::string filename
int width
int size
int height
QStringList qtCompatSplitRegex(const QString &str, const QString &pattern, Qt::SplitBehavior behavior=Qt::KeepEmptyParts)
Definition: QtCompat.h:308
cmdLineReadable * params[]
void updateOverlayGrid()
Updates overlat grid (if any)
ccColorScaleSelector * m_colorScaleSelector
Color scale selector.
ccPointCloud * m_cloud
Associated cloud.
DistanceMapGenerationTool::EmptyCellFillOption getEmptyCellFillingOption() const
Returns the empty cells filling option.
ccSymbolCloud * m_xLabels
X labels.
double getBaseRadius() const
Returns currently applicable base radius.
DistanceMapGenerationDlg(ccPointCloud *cloud, ccScalarField *sf, ccPolyline *polyline, ecvMainAppInterface *app=0)
Default constructor.
void updateMinAndMaxLimits()
Updates the min and max limits (fields)
ANGULAR_UNIT getAngularUnit() const
Returns selected angular unit.
void getGridXValues(double &minX, double &maxX, double &step, ANGULAR_UNIT unit=ANG_RAD) const
Returns the current 'X' parameters.
double getSpinboxAngularValue(QDoubleSpinBox *spinBox, DistanceMapGenerationDlg::ANGULAR_UNIT unit) const
Returns the angle in a particular spinbox in the specified units.
void clearView()
Clears the 3D view.
QSharedPointer< DistanceMapGenerationTool::Map > m_map
Internal map structure.
ccPolyline * m_profile
Associated profile.
void update()
Updates map (and display)
QString getAngularUnitString() const
Returns selected angular unit as a string.
ccMapWindow * m_window
2D display
ccScalarField * m_sf
Associated scalar field.
DistanceMapGenerationTool::FillStrategyType getFillingStrategy() const
Returns the grid filling strategy.
QSharedPointer< DistanceMapGenerationTool::Map > updateMap()
Updates internal map.
QColor m_symbolColor
Symbols color.
ProjectionMode getProjectionMode() const
Returns current projection mode.
double getScaleYStep(ANGULAR_UNIT unit=ANG_RAD) const
Returns scale 'Y' step (current unit)
void getGridYValues(double &minY, double &maxY, double &step, ANGULAR_UNIT unit=ANG_RAD) const
Returns the current 'Y' parameters.
void saveToPersistentSettings()
Saves parameters to persistent settings.
void updateMapTexture()
Updates internal map texture (if any)
QString getHeightUnitString() const
Returns height unit.
QString getCondensedAngularUnitString() const
Returns selected angular unit as a condensed string.
void initFromPersistentSettings()
Loads parameters from persistent settings.
void updateZoom(ccBBox &box)
Updates 2D view zoom.
ANGULAR_UNIT m_angularUnits
Current angular units.
ecvMainAppInterface * m_app
Application interface.
ccSymbolCloud * m_yLabels
Y labels.
virtual ~DistanceMapGenerationDlg()
Default destructor.
EmptyCellFillOption
Option for handling empty cells.
static bool SaveMapAsCSVMatrix(const QSharedPointer< Map > &map, QString filename, QString xUnit, QString yUnit, double xConversionFactor=1.0, double yConversionFactor=1.0, ecvMainAppInterface *app=0)
Saves a map as a CSV matrix.
static ccPointCloud * ConvertMapToCloud(const QSharedPointer< Map > &map, ccPolyline *profile, double baseRadius=1.0, bool keepNaNPoints=true)
Converts map to a point cloud.
static void SetPoylineOrigin(ccPolyline *polyline, const CCVector3 &origin)
Sets the origin of a given polyline/profile.
static ccMesh * ConvertProfileToMesh(ccPolyline *profile, const ccGLMatrix &cloudToProfile, bool counterclockwise, unsigned angularSteps=36, QImage mapTexture=QImage())
Converts profile to a (textured) mesh.
static QImage ConvertMapToImage(const QSharedPointer< Map > &map, ccColorScale::Shared colorScale, unsigned colorScaleSteps=ccColorScale::MAX_STEPS)
Converts map to a QImage.
static void SetPoylineRevolDim(ccPolyline *polyline, int revolDim)
Sets the revolution dimension of a given polyline.
static bool ComputeMinAndMaxLatitude_rad(ccPointCloud *cloud, double &minLat_rad, double &maxLat_rad, const ccGLMatrix &cloudToSurfaceOrigin, unsigned char revolutionAxisDim)
static bool ConvertCloudToConical(ccPointCloud *cloud, const ccGLMatrix &cloudToSurface, unsigned char revolutionAxisDim, double latMin_rad, double latMax_rad, double conicalSpanRatio=1.0, bool counterclockwise=false)
Converts a point cloud coordinates to "conical" ones (in place)
static double ConicalProjectN(double phi1, double phi2)
static void SetPolylineHeightShift(ccPolyline *polyline, PointCoordinateType heightShift)
Sets the profile 'height shift' (i.e. along the revolution axis)
static bool GetPolylineHeightShift(const ccPolyline *polyline, PointCoordinateType &heightShift)
Returns the profile 'height shift' (i.e. along the revolution axis)
static bool ComputeSurfacesAndVolumes(const QSharedPointer< Map > &map, ccPolyline *profile, Measures &surfaces, Measures &volumes)
FillStrategyType
Grid filling strategy.
static bool ConvertCloudToCylindrical(ccPointCloud *cloud, const ccGLMatrix &cloudToSurface, unsigned char revolutionAxisDim, bool counterclockwise=false)
Converts a point cloud coordinates to "cylindrical" ones (in place)
static QSharedPointer< Map > CreateMap(ccPointCloud *cloud, ccScalarField *sf, const ccGLMatrix &cloudToSurface, unsigned char revolutionAxisDim, double angStep_rad, double yStep, double yMin, double yMax, bool conical, bool counterclockwise, FillStrategyType fillStrategy, EmptyCellFillOption emptyCellfillOption, ecvMainAppInterface *app=0)
static bool GetPoylineMetaData(const ccPolyline *polyline, ProfileMetaData &data)
static CCVector3 ProjectPointOnCone(double lon_rad, double lat_rad, double latMin_rad, double nProj, bool counterclockwise)
Projects a (longitude,r) couple to a 2D map.
static ccMesh * ConvertConicalMapToMesh(const QSharedPointer< Map > &map, bool counterclockwise, QImage mapTexture=QImage())
Creates a conical projection (textured) mesh.
Dialog for export multiple 2D profiles in a single DXF file (qSRA plugin)
QString getHorizFilename() const
Returns horiz. profiles output filename (on completion)
QString getVertFilename() const
Returns vert. profiles output filename (on completion)
static bool SaveHorizontalProfiles(const QSharedPointer< DistanceMapGenerationTool::Map > &map, ccPolyline *profile, QString filename, unsigned heightStepCount, double heightShift, double angularStep_rad, double radToUnitConvFactor, QString angleUnit, const Parameters &params, ecvMainAppInterface *app=0)
static bool SaveVerticalProfiles(const QSharedPointer< DistanceMapGenerationTool::Map > &map, ccPolyline *profile, QString filename, unsigned angularStepCount, double heightStep, double heightShift, const Parameters &params, ecvMainAppInterface *app=0)
static bool IsEnabled()
Returns whether DXF support is enabled or not.
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
Bounding box structure.
Definition: ecvBBox.h:25
Dialog to edit/create color scales.
ccColorScale::Shared getActiveScale()
Returns active scale.
Advanced editor for color scales.
void init()
Inits selector with the Color Scales Manager.
void setSelectedScale(QString uuid)
Sets selected combo box item (scale) by UUID.
ccColorScale::Shared getSelectedScale() const
Returns currently selected color scale.
static const unsigned MIN_STEPS
Minimum number of steps.
Definition: ecvColorScale.h:99
QSharedPointer< ccColorScale > Shared
Shared pointer type.
Definition: ecvColorScale.h:74
static const unsigned MAX_STEPS
Maximum number of steps (internal representation)
static ccColorScale::Shared GetDefaultScale(DEFAULT_SCALES scale=BGYR)
Returns a pre-defined color scale (static shortcut)
void toPersistentSettings() const
Save custom color scales to persistent settings.
ccColorScale::Shared getDefaultScale(DEFAULT_SCALES scale) const
Returns a pre-defined color scale.
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual void setTempColor(const ecvColor::Rgb &col, bool autoActivate=true)
Sets current temporary (unique)
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
void setTranslation(const Vector3Tpl< float > &Tr)
Sets translation (float version)
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
void showNormals(bool state) override
Sets normals visibility.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual ccBBox getDisplayBB_recursive(bool relative)
Returns the bounding-box of this entity and it's children WHEN DISPLAYED.
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
2D map display window
Definition: ccMapWindow.h:15
bool sfShown() const
Returns whether associated SF should be shown or not.
Definition: ccMapWindow.h:41
void showSF(bool state)
Whether to show associated SF or not.
Definition: ccMapWindow.h:38
void setAssociatedScalarField(ccScalarField *sf)
Sets associated scalar-field.
Definition: ccMapWindow.h:27
ccScalarField * getAssociatedScalarField() const
Returns associated scalar field.
Definition: ccMapWindow.h:44
Triangular mesh.
Definition: ecvMesh.h:35
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
Plane (primitive)
Definition: ecvPlane.h:18
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
void shrinkToFit()
Removes unused capacity.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
Colored polyline.
Definition: ecvPolyline.h:24
void set2DMode(bool state)
Defines if the polyline is considered as 2D or 3D.
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Definition: ecvPolyline.h:81
static void SetButtonColor(QAbstractButton *button, const QColor &col)
Sets a button background color.
Definition: ecvQtHelpers.h:17
Dialog for screen to file rendering.
void hideOptions()
Disable and hide the scale and overlay checkboxes.
bool dontScalePoints() const
On dialog acceptance, returns whether points should be scaled or not.
bool renderOverlayItems() const
Whether overlay items should be rendered.
float getZoom() const
On dialog acceptance, returns requested zoom.
QString getFilename() const
On dialog acceptance, returns requested output filename.
A scalar field associated to display-related parameters.
const ccColorScale::Shared & getColorScale() const
Returns associated color scale.
void setColorRampSteps(unsigned steps)
Sets number of color ramp steps used for display.
void setColorScale(ccColorScale::Shared scale)
Sets associated color scale.
void computeMinAndMax() override
Determines the min and max values.
void setLabelAlignmentFlags(unsigned char flags)
Sets labels alignment flags.
Definition: ccSymbolCloud.h:75
int getFontSize() const
Returns label font size.
Definition: ccSymbolCloud.h:60
QString getLabel(unsigned index) const
Returns a given label.
void addLabel(QString label)
Adds a label.
virtual void clear() override
Clears the entity from all its points and features.
virtual bool reserve(unsigned numberOfPoints) override
inherited from ccPointCloud
void showSymbols(bool state)
Sets whether symbols should be displayed or not.
Definition: ccSymbolCloud.h:63
void setSymbolSize(double size)
Sets symbol size.
Definition: ccSymbolCloud.h:51
bool reserveLabelArray(unsigned count)
Reserves memory for storing per-point labels.
void setFontSize(int size)
Sets label font size.
Definition: ccSymbolCloud.h:57
Vector3Tpl< T > getDiagVec() const
Returns diagonal vector.
Definition: BoundingBox.h:169
Vector3Tpl< T > getCenter() const
Returns center.
Definition: BoundingBox.h:164
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
Definition: BoundingBox.h:156
T getDiagNorm() const
Returns diagonal length.
Definition: BoundingBox.h:172
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Definition: PointCloudTpl.h:38
unsigned capacity() const
Returns cloud capacity (i.e. reserved size)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
unsigned size() const override
Returns the number of points.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
void addElement(ScalarType value)
Definition: ScalarField.h:99
void setName(const char *name)
Sets scalar field name.
Definition: ScalarField.cpp:22
RGB color structure.
Definition: ecvColorTypes.h:49
static bool RenderToFile(QString filename, float zoomFactor=1.0f, bool dontScaleFeatures=false, bool renderOverlayItems=false)
Renders screen to a file.
static void RemoveFromOwnDB(ccHObject *obj)
Removes an entity from window own DB.
static void AddToOwnDB(ccHObject *obj, bool noDependency=true)
Adds an entity to window own DB.
static const ecvGui::ParamStruct & GetDisplayParameters()
Returns current parameters for this display (const version)
static void SetDisplayParameters(const ecvGui::ParamStruct &params)
Sets current parameters for this display.
static QFont GetTextDisplayFont()
static void InvalidateViewport()
static const ecvViewportParameters & GetViewportParameters()
static int GlWidth()
Returns the OpenGL context width.
static void SetCameraPos(const CCVector3d &P)
Sets camera position.
static void Deprecate3DLayer()
static void DisplayOverlayEntities(bool state)
static void SetViewportParameters(const ecvViewportParameters &params)
static int GlHeight()
Returns the OpenGL context height.
static void SetInteractionMode(INTERACTION_FLAGS flags)
static ccHObject * GetOwnDB()
Returns window own DB.
static void SetPerspectiveState(bool state, bool objectCenteredView)
Set perspective state/mode.
static void SetPivotPoint(const CCVector3d &P, bool autoUpdateCameraPos=false, bool verbose=false)
Sets pivot point.
static void InvalidateVisualization()
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
Main application interface (for plugins)
virtual QMainWindow * getMainWindow()=0
Returns main window.
virtual void addToDB(ccHObject *obj, bool updateZoom=false, bool autoExpandDBTree=true, bool checkDimensions=false, bool autoRedraw=true)=0
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
virtual ccColorScalesManager * getColorScalesManager()=0
Returns color scale manager (unique instance)
Standard parameters for GL displays/viewports.
int max(int a, int b)
Definition: cutil_math.h:48
static const double DEFAULT_LABEL_MARGIN
static double ConvertAngleToRad(double angle, DistanceMapGenerationDlg::ANGULAR_UNIT srcUnit)
static double ConvertAngleFromRad(double angle_rad, DistanceMapGenerationDlg::ANGULAR_UNIT destUnit)
static void SetSpinBoxValues(QDoubleSpinBox *spinBox, int decimals, double minVal, double maxVal, double step, double value)
static const char YLABEL_CLOUD_NAME[]
static const char XLABEL_CLOUD_NAME[]
unsigned char ColorCompType
Default color components type (R,G and B)
Definition: ecvColorTypes.h:29
static void error(char *msg)
Definition: lsd.c:159
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
@ POLY_LINE
Definition: CVTypes.h:112
@ PLANE
Definition: CVTypes.h:120
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
bool setColor(ccHObject::Container selectedEntities, bool colorize, QWidget *parent)
static const std::string path
Definition: PointCloud.cpp:59
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
float RadiansToDegrees(int radians)
Convert radians to degrees.
Definition: CVMath.h:71
bool GreaterThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:37
float DegreesToRadians(int degrees)
Convert degrees to radians.
Definition: CVMath.h:98
constexpr Rgb black(0, 0, 0)
constexpr Rgb white(MAX, MAX, MAX)
QString defaultDocPath()
Shortcut for getting the documents location path.
Definition: ecvFileUtils.h:30
int revolDim
revolution axis (X=0, Y=1, Z=2)
CCVector3 origin
origin of the surface of revolution
GUI parameters.
unsigned colorScaleRampWidth
Color scale ramp width (for display)