13 #include <vtkAxisActor2D.h>
14 #include <vtkCommand.h>
15 #include <vtkHandleRepresentation.h>
16 #include <vtkLineRepresentation.h>
18 #include <vtkPointHandleRepresentation3D.h>
19 #include <vtkProperty.h>
20 #include <vtkProperty2D.h>
21 #include <vtkRenderWindow.h>
22 #include <vtkRenderWindowInteractor.h>
23 #include <vtkRenderer.h>
24 #include <vtkTextProperty.h>
26 #include <QApplication>
28 #include <QLayoutItem>
30 #include <QSizePolicy>
60 auto* h1 = vtkPointHandleRepresentation3D::SafeDownCast(
61 rep->GetPoint1Representation());
62 auto* h2 = vtkPointHandleRepresentation3D::SafeDownCast(
63 rep->GetPoint2Representation());
64 auto* hLine = vtkPointHandleRepresentation3D::SafeDownCast(
65 rep->GetLineHandleRepresentation());
71 if (
auto* lineProp = rep->GetLineProperty()) {
74 lineProp->SetLineWidth(2.0);
75 lineProp->SetAmbient(1.0);
79 if (
auto* axis = rep->GetAxisActor()) {
81 if (
auto* titleProp = axis->GetTitleTextProperty()) {
82 titleProp->SetFontSize(
84 titleProp->SetBold(0);
85 titleProp->SetShadow(1);
86 titleProp->SetColor(1.0, 1.0, 1.0);
90 if (
auto* labelProp = axis->GetLabelTextProperty()) {
91 labelProp->SetFontSize(
93 labelProp->SetBold(0);
94 labelProp->SetShadow(1);
95 labelProp->SetColor(1.0, 1.0, 1.0);
100 rep->SetShowLabel(1);
101 rep->SetLabelFormat(
"%-#6.3g");
102 rep->SetRulerMode(0);
103 rep->SetRulerDistance(1.0);
104 rep->SetNumberOfRulerTicks(5);
112 setWindowTitle(tr(
"Distance Measurement Tool"));
120 m_widget->SetEnabled(0);
125 m_rep->SetVisibility(0);
135 m_configUi =
nullptr;
146 m_widget->SetRepresentation(m_rep);
160 m_rep->ReplaceHandleRepresentationsTyped<
164 configureLineRepresentation(m_rep);
167 if (
auto* lineProp = m_rep->GetLineProperty()) {
168 lineProp->SetColor(m_currentColor[0], m_currentColor[1],
171 if (
auto* selectedLineProp = m_rep->GetSelectedLineProperty()) {
172 selectedLineProp->SetColor(m_currentColor[0], m_currentColor[1],
178 double defaultPos1[3] = {0.0, 0.0, 0.0};
179 double defaultPos2[3] = {1.0, 0.0, 0.0};
189 double diagLength = diag.
norm();
190 double offset = diagLength * 0.3;
200 defaultPos1[0] = center.
x - diag.
x * 0.25;
201 defaultPos1[1] = center.
y +
offset;
202 defaultPos1[2] = center.
z +
offset;
204 defaultPos2[0] = center.
x + diag.
x * 0.25;
205 defaultPos2[1] = center.
y +
offset;
206 defaultPos2[2] = center.
z +
offset;
209 m_rep->SetPoint1WorldPosition(defaultPos1);
210 m_rep->SetPoint2WorldPosition(defaultPos2);
213 m_rep->BuildRepresentation();
218 applyFontProperties();
229 m_configUi->point1XSpinBox->setValue(defaultPos1[0]);
230 m_configUi->point1YSpinBox->setValue(defaultPos1[1]);
231 m_configUi->point1ZSpinBox->setValue(defaultPos1[2]);
232 m_configUi->point2XSpinBox->setValue(defaultPos2[0]);
233 m_configUi->point2YSpinBox->setValue(defaultPos2[1]);
234 m_configUi->point2ZSpinBox->setValue(defaultPos2[2]);
237 updateDistanceDisplay();
243 hookWidget(m_widget);
254 CVLog::Error(
"[cvDistanceTool::createUi] m_ui is null!");
264 if (m_configUi &&
m_ui->configLayout) {
267 while ((item =
m_ui->configLayout->takeAt(0)) !=
nullptr) {
268 if (item->widget()) {
269 item->widget()->setParent(
nullptr);
270 item->widget()->deleteLater();
275 m_configUi =
nullptr;
279 m_configUi =
new Ui::DistanceToolDlg;
280 QWidget* configWidget =
new QWidget(
this);
284 m_configUi->setupUi(configWidget);
287 if (configWidget->layout()) {
288 configWidget->layout()->setSizeConstraint(QLayout::SetMinimumSize);
290 m_ui->configLayout->addWidget(configWidget);
291 m_ui->groupBox->setTitle(tr(
"Distance Parameters"));
293 m_configUi->distanceSpinBox->setValue(1.0);
296 m_configUi->instructionLabel->setText(
297 m_configUi->instructionLabel->text().replace(
"Ctrl",
"Cmd"));
304 if (m_configUi->instructionLabel) {
312 m_configUi->instructionLabel->setMaximumHeight(
316 m_configUi->instructionLabel->setMaximumWidth(
318 m_configUi->instructionLabel->setWordWrap(
true);
321 m_configUi->instructionLabel->adjustSize();
323 m_configUi->instructionLabel->updateGeometry();
330 this->setMinimumSize(0, 0);
331 this->setMaximumSize(16777215, 16777215);
336 configWidget->adjustSize();
339 this->updateGeometry();
341 QApplication::processEvents();
343 connect(m_configUi->point1XSpinBox,
344 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
345 &cvDistanceTool::on_point1XSpinBox_valueChanged);
346 connect(m_configUi->point1YSpinBox,
347 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
348 &cvDistanceTool::on_point1YSpinBox_valueChanged);
349 connect(m_configUi->point1ZSpinBox,
350 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
351 &cvDistanceTool::on_point1ZSpinBox_valueChanged);
352 connect(m_configUi->point2XSpinBox,
353 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
354 &cvDistanceTool::on_point2XSpinBox_valueChanged);
355 connect(m_configUi->point2YSpinBox,
356 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
357 &cvDistanceTool::on_point2YSpinBox_valueChanged);
358 connect(m_configUi->point2ZSpinBox,
359 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
360 &cvDistanceTool::on_point2ZSpinBox_valueChanged);
363 connect(m_configUi->pickPoint1ToolButton, &QToolButton::toggled,
this,
364 &cvDistanceTool::on_pickPoint1_toggled);
365 connect(m_configUi->pickPoint2ToolButton, &QToolButton::toggled,
this,
366 &cvDistanceTool::on_pickPoint2_toggled);
369 connect(m_configUi->rulerModeCheckBox, &QCheckBox::toggled,
this,
370 &cvDistanceTool::on_rulerModeCheckBox_toggled);
371 connect(m_configUi->rulerDistanceSpinBox,
372 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
373 &cvDistanceTool::on_rulerDistanceSpinBox_valueChanged);
374 connect(m_configUi->numberOfTicksSpinBox,
375 QOverload<int>::of(&QSpinBox::valueChanged),
this,
376 &cvDistanceTool::on_numberOfTicksSpinBox_valueChanged);
377 connect(m_configUi->scaleSpinBox,
378 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
379 &cvDistanceTool::on_scaleSpinBox_valueChanged);
380 connect(m_configUi->labelFormatLineEdit, &QLineEdit::textChanged,
this,
381 &cvDistanceTool::on_labelFormatLineEdit_textChanged);
384 connect(m_configUi->widgetVisibilityCheckBox, &QCheckBox::toggled,
this,
385 &cvDistanceTool::on_widgetVisibilityCheckBox_toggled);
386 connect(m_configUi->labelVisibilityCheckBox, &QCheckBox::toggled,
this,
387 &cvDistanceTool::on_labelVisibilityCheckBox_toggled);
388 connect(m_configUi->lineWidthSpinBox,
389 QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this,
390 &cvDistanceTool::on_lineWidthSpinBox_valueChanged);
398 double defaultPos1[3] = {0.0, 0.0, 0.0};
399 double defaultPos2[3] = {1.0, 0.0, 0.0};
409 double diagLength = diag.
norm();
410 double offset = diagLength * 0.3;
420 defaultPos1[0] = center.
x - diag.
x * 0.25;
421 defaultPos1[1] = center.
y +
offset;
422 defaultPos1[2] = center.
z +
offset;
424 defaultPos2[0] = center.
x + diag.
x * 0.25;
425 defaultPos2[1] = center.
y +
offset;
426 defaultPos2[2] = center.
z +
offset;
430 if (m_widget && m_widget->GetEnabled()) {
431 m_rep->SetPoint1WorldPosition(defaultPos1);
432 m_rep->SetPoint2WorldPosition(defaultPos2);
433 m_rep->BuildRepresentation();
434 m_widget->Modified();
446 m_configUi->point1XSpinBox->setValue(defaultPos1[0]);
447 m_configUi->point1YSpinBox->setValue(defaultPos1[1]);
448 m_configUi->point1ZSpinBox->setValue(defaultPos1[2]);
449 m_configUi->point2XSpinBox->setValue(defaultPos2[0]);
450 m_configUi->point2YSpinBox->setValue(defaultPos2[1]);
451 m_configUi->point2ZSpinBox->setValue(defaultPos2[2]);
475 "[cvDistanceTool::getOutput] No entity associated with this "
496 if (!cloud || cloud->
size() == 0) {
498 "[cvDistanceTool::getOutput] Could not find associated point "
499 "cloud or cloud is empty");
516 unsigned nearestIndex1 = 0;
517 unsigned nearestIndex2 = 0;
518 double minDist1 = std::numeric_limits<double>::max();
519 double minDist2 = std::numeric_limits<double>::max();
523 const double DISTANCE_THRESHOLD = 0.001;
525 for (
unsigned i = 0; i < cloud->
size(); ++i) {
529 double d1 = (*P - point1).norm();
535 double d2 = (*P - point2).norm();
549 unsigned pointsToAdd = 0;
550 if (minDist1 > DISTANCE_THRESHOLD) pointsToAdd++;
551 if (minDist2 > DISTANCE_THRESHOLD) pointsToAdd++;
554 if (pointsToAdd > 0) {
555 unsigned currentSize = pointCloud->
size();
556 if (pointCloud->
reserve(currentSize + pointsToAdd)) {
558 if (minDist1 > DISTANCE_THRESHOLD) {
560 nearestIndex1 = pointCloud->
size() - 1;
564 if (minDist2 > DISTANCE_THRESHOLD) {
566 nearestIndex2 = pointCloud->
size() - 1;
579 "[cvDistanceTool::getOutput] Failed to add first point to "
587 "[cvDistanceTool::getOutput] Failed to add second point to "
608 return m_configUi->distanceSpinBox->value();
614 if (m_configUi && pos) {
615 pos[0] = m_configUi->point1XSpinBox->value();
616 pos[1] = m_configUi->point1YSpinBox->value();
617 pos[2] = m_configUi->point1ZSpinBox->value();
619 pos[0] = pos[1] = pos[2] = 0.0;
624 if (m_configUi && pos) {
625 pos[0] = m_configUi->point2XSpinBox->value();
626 pos[1] = m_configUi->point2YSpinBox->value();
627 pos[2] = m_configUi->point2ZSpinBox->value();
629 pos[0] = pos[1] = pos[2] = 0.0;
635 CVLog::Warning(
"[cvDistanceTool] setPoint1: m_configUi or pos is null");
640 if (m_configUi->pickPoint1ToolButton->isChecked()) {
641 m_configUi->pickPoint1ToolButton->setChecked(
false);
648 m_configUi->point1XSpinBox->setValue(pos[0]);
649 m_configUi->point1YSpinBox->setValue(pos[1]);
650 m_configUi->point1ZSpinBox->setValue(pos[2]);
653 if (m_widget && m_widget->GetEnabled()) {
654 m_rep->SetPoint1WorldPosition(pos);
655 m_rep->BuildRepresentation();
656 m_widget->Modified();
661 updateDistanceDisplay();
667 CVLog::Warning(
"[cvDistanceTool] setPoint2: m_configUi or pos is null");
672 if (m_configUi->pickPoint2ToolButton->isChecked()) {
673 m_configUi->pickPoint2ToolButton->setChecked(
false);
680 m_configUi->point2XSpinBox->setValue(pos[0]);
681 m_configUi->point2YSpinBox->setValue(pos[1]);
682 m_configUi->point2ZSpinBox->setValue(pos[2]);
685 if (m_widget && m_widget->GetEnabled()) {
686 m_rep->SetPoint2WorldPosition(pos);
687 m_rep->BuildRepresentation();
688 m_widget->Modified();
693 updateDistanceDisplay();
699 m_currentColor[0] = r;
700 m_currentColor[1] = g;
701 m_currentColor[2] = b;
705 if (
auto* lineProp = m_rep->GetLineProperty()) {
706 lineProp->SetColor(r, g, b);
708 if (
auto* selectedLineProp = m_rep->GetSelectedLineProperty()) {
709 selectedLineProp->SetColor(r, g, b);
711 m_rep->BuildRepresentation();
713 m_widget->Modified();
720 r = m_currentColor[0];
721 g = m_currentColor[1];
722 b = m_currentColor[2];
728 "m_pickingHelpers.size()=%2")
729 .arg((quintptr)
this, 0, 16)
734 m_widget->SetProcessEvents(0);
742 if (
auto* lineProp = m_rep->GetLineProperty()) {
743 lineProp->SetColor(m_currentColor[0] * 0.1, m_currentColor[1] * 0.1,
744 m_currentColor[2] * 0.1);
745 lineProp->SetOpacity(0.5);
747 if (
auto* selectedLineProp = m_rep->GetSelectedLineProperty()) {
748 selectedLineProp->SetColor(m_currentColor[0] * 0.1,
749 m_currentColor[1] * 0.1,
750 m_currentColor[2] * 0.1);
751 selectedLineProp->SetOpacity(0.5);
756 if (
auto* point1Rep =
dynamic_cast<vtkPointHandleRepresentation3D*
>(
757 m_rep->GetPoint1Representation())) {
758 if (
auto* prop = point1Rep->GetProperty()) {
759 prop->SetOpacity(0.5);
761 if (
auto* selectedProp = point1Rep->GetSelectedProperty()) {
762 selectedProp->SetOpacity(0.5);
765 if (
auto* point2Rep =
dynamic_cast<vtkPointHandleRepresentation3D*
>(
766 m_rep->GetPoint2Representation())) {
767 if (
auto* prop = point2Rep->GetProperty()) {
768 prop->SetOpacity(0.5);
770 if (
auto* selectedProp = point2Rep->GetSelectedProperty()) {
771 selectedProp->SetOpacity(0.5);
775 m_rep->BuildRepresentation();
779 if (
auto* axis = m_rep->GetAxisActor()) {
781 if (
auto* axisProp = axis->GetProperty()) {
782 axisProp->SetOpacity(0.5);
786 if (
auto* titleProp = axis->GetTitleTextProperty()) {
787 titleProp->SetOpacity(0.5);
788 titleProp->SetColor(0.5, 0.5,
793 if (
auto* labelProp = axis->GetLabelTextProperty()) {
794 labelProp->SetOpacity(0.5);
799 m_widget->Modified();
811 m_configUi->point1XSpinBox->setEnabled(
false);
812 m_configUi->point1YSpinBox->setEnabled(
false);
813 m_configUi->point1ZSpinBox->setEnabled(
false);
814 m_configUi->point2XSpinBox->setEnabled(
false);
815 m_configUi->point2YSpinBox->setEnabled(
false);
816 m_configUi->point2ZSpinBox->setEnabled(
false);
817 m_configUi->pickPoint1ToolButton->setEnabled(
false);
818 m_configUi->pickPoint2ToolButton->setEnabled(
false);
819 m_configUi->rulerModeCheckBox->setEnabled(
false);
820 m_configUi->rulerDistanceSpinBox->setEnabled(
false);
821 m_configUi->numberOfTicksSpinBox->setEnabled(
false);
822 m_configUi->scaleSpinBox->setEnabled(
false);
823 m_configUi->labelFormatLineEdit->setEnabled(
false);
824 m_configUi->widgetVisibilityCheckBox->setEnabled(
false);
825 m_configUi->labelVisibilityCheckBox->setEnabled(
false);
826 m_configUi->lineWidthSpinBox->setEnabled(
false);
836 m_widget->SetProcessEvents(1);
842 if (
auto* lineProp = m_rep->GetLineProperty()) {
843 lineProp->SetColor(m_currentColor[0], m_currentColor[1],
845 lineProp->SetOpacity(1.0);
847 if (
auto* selectedLineProp = m_rep->GetSelectedLineProperty()) {
848 selectedLineProp->SetColor(m_currentColor[0], m_currentColor[1],
850 selectedLineProp->SetOpacity(1.0);
855 if (
auto* point1Rep =
dynamic_cast<vtkPointHandleRepresentation3D*
>(
856 m_rep->GetPoint1Representation())) {
857 if (
auto* prop = point1Rep->GetProperty()) {
858 prop->SetOpacity(1.0);
860 if (
auto* selectedProp = point1Rep->GetSelectedProperty()) {
861 selectedProp->SetOpacity(1.0);
864 if (
auto* point2Rep =
dynamic_cast<vtkPointHandleRepresentation3D*
>(
865 m_rep->GetPoint2Representation())) {
866 if (
auto* prop = point2Rep->GetProperty()) {
867 prop->SetOpacity(1.0);
869 if (
auto* selectedProp = point2Rep->GetSelectedProperty()) {
870 selectedProp->SetOpacity(1.0);
874 m_rep->BuildRepresentation();
878 if (
auto* axis = m_rep->GetAxisActor()) {
880 if (
auto* axisProp = axis->GetProperty()) {
881 axisProp->SetOpacity(1.0);
885 if (
auto* titleProp = axis->GetTitleTextProperty()) {
892 if (
auto* labelProp = axis->GetLabelTextProperty()) {
900 m_widget->Modified();
912 m_configUi->point1XSpinBox->setEnabled(
true);
913 m_configUi->point1YSpinBox->setEnabled(
true);
914 m_configUi->point1ZSpinBox->setEnabled(
true);
915 m_configUi->point2XSpinBox->setEnabled(
true);
916 m_configUi->point2YSpinBox->setEnabled(
true);
917 m_configUi->point2ZSpinBox->setEnabled(
true);
918 m_configUi->pickPoint1ToolButton->setEnabled(
true);
919 m_configUi->pickPoint2ToolButton->setEnabled(
true);
920 m_configUi->rulerModeCheckBox->setEnabled(
true);
923 bool rulerMode = m_configUi->rulerModeCheckBox->isChecked();
924 m_configUi->rulerDistanceSpinBox->setEnabled(rulerMode);
925 m_configUi->numberOfTicksSpinBox->setEnabled(!rulerMode);
927 m_configUi->scaleSpinBox->setEnabled(
true);
928 m_configUi->labelFormatLineEdit->setEnabled(
true);
929 m_configUi->widgetVisibilityCheckBox->setEnabled(
true);
930 m_configUi->labelVisibilityCheckBox->setEnabled(
true);
931 m_configUi->lineWidthSpinBox->setEnabled(
true);
938 QString(
"[cvDistanceTool::unlockInteraction] Creating "
939 "shortcuts for tool=%1, using saved vtkWidget=%2")
940 .arg((quintptr)
this, 0, 16)
944 QString(
"[cvDistanceTool::unlockInteraction] After "
945 "setupShortcuts, m_pickingHelpers.size()=%1")
949 QString(
"[cvDistanceTool::unlockInteraction] m_vtkWidget "
950 "is null for tool=%1, cannot create shortcuts")
951 .arg((quintptr)
this, 0, 16));
956 "Enabling %1 existing shortcuts for tool=%2")
958 .arg((quintptr)
this, 0, 16));
961 helper->setEnabled(
true,
970 m_instanceLabel = label;
974 m_rep->SetLabelSuffix(m_instanceLabel.toUtf8().constData());
975 m_rep->BuildRepresentation();
977 m_widget->Modified();
983 void cvDistanceTool::on_point1XSpinBox_valueChanged(
double arg1) {
984 if (!m_configUi)
return;
991 if (m_widget && m_widget->GetEnabled()) {
992 m_rep->GetPoint1WorldPosition(pos);
995 m_rep->SetPoint1WorldPosition(newPos);
996 m_rep->BuildRepresentation();
997 m_widget->Modified();
998 updateDistanceDisplay();
1003 void cvDistanceTool::on_point1YSpinBox_valueChanged(
double arg1) {
1004 if (!m_configUi)
return;
1011 if (m_widget && m_widget->GetEnabled()) {
1012 m_rep->GetPoint1WorldPosition(pos);
1015 m_rep->SetPoint1WorldPosition(newPos);
1016 m_rep->BuildRepresentation();
1017 m_widget->Modified();
1018 updateDistanceDisplay();
1023 void cvDistanceTool::on_point1ZSpinBox_valueChanged(
double arg1) {
1024 if (!m_configUi)
return;
1031 if (m_widget && m_widget->GetEnabled()) {
1032 m_rep->GetPoint1WorldPosition(pos);
1035 m_rep->SetPoint1WorldPosition(newPos);
1036 m_rep->BuildRepresentation();
1037 m_widget->Modified();
1038 updateDistanceDisplay();
1043 void cvDistanceTool::on_point2XSpinBox_valueChanged(
double arg1) {
1044 if (!m_configUi)
return;
1051 if (m_widget && m_widget->GetEnabled()) {
1052 m_rep->GetPoint2WorldPosition(pos);
1055 m_rep->SetPoint2WorldPosition(newPos);
1056 m_rep->BuildRepresentation();
1057 m_widget->Modified();
1058 updateDistanceDisplay();
1063 void cvDistanceTool::on_point2YSpinBox_valueChanged(
double arg1) {
1064 if (!m_configUi)
return;
1071 if (m_widget && m_widget->GetEnabled()) {
1072 m_rep->GetPoint2WorldPosition(pos);
1075 m_rep->SetPoint2WorldPosition(newPos);
1076 m_rep->BuildRepresentation();
1077 m_widget->Modified();
1078 updateDistanceDisplay();
1083 void cvDistanceTool::on_point2ZSpinBox_valueChanged(
double arg1) {
1084 if (!m_configUi)
return;
1091 if (m_widget && m_widget->GetEnabled()) {
1092 m_rep->GetPoint2WorldPosition(pos);
1095 m_rep->SetPoint2WorldPosition(newPos);
1096 m_rep->BuildRepresentation();
1097 m_widget->Modified();
1098 updateDistanceDisplay();
1103 void cvDistanceTool::onDistanceChanged(
double dist) {
1104 if (!m_configUi)
return;
1108 double scale = m_configUi->scaleSpinBox->value();
1109 double scaledDistance = dist * scale;
1112 m_configUi->distanceSpinBox->setValue(scaledDistance);
1116 void cvDistanceTool::onWorldPoint1Changed(
double* pos) {
1117 if (!m_configUi || !pos)
return;
1121 m_configUi->point1XSpinBox->setValue(pos[0]);
1122 m_configUi->point1YSpinBox->setValue(pos[1]);
1123 m_configUi->point1ZSpinBox->setValue(pos[2]);
1127 void cvDistanceTool::onWorldPoint2Changed(
double* pos) {
1128 if (!m_configUi || !pos)
return;
1132 m_configUi->point2XSpinBox->setValue(pos[0]);
1133 m_configUi->point2YSpinBox->setValue(pos[1]);
1134 m_configUi->point2ZSpinBox->setValue(pos[2]);
1138 void cvDistanceTool::hookWidget(
1142 observer->
attach(widget.Get());
1144 &cvDistanceTool::onDistanceChanged);
1146 this, &cvDistanceTool::onWorldPoint1Changed);
1148 this, &cvDistanceTool::onWorldPoint2Changed);
1151 void cvDistanceTool::updateDistanceDisplay() {
1152 if (!m_configUi)
return;
1155 double scale = m_configUi->scaleSpinBox->value();
1159 distance = m_rep->GetDistance() * scale;
1163 m_configUi->distanceSpinBox->setValue(
distance);
1167 void cvDistanceTool::on_pickPoint1_toggled(
bool checked) {
1170 if (m_configUi->pickPoint2ToolButton->isChecked()) {
1171 m_configUi->pickPoint2ToolButton->setChecked(
false);
1181 void cvDistanceTool::on_pickPoint2_toggled(
bool checked) {
1184 if (m_configUi->pickPoint1ToolButton->isChecked()) {
1185 m_configUi->pickPoint1ToolButton->setChecked(
false);
1195 void cvDistanceTool::on_rulerModeCheckBox_toggled(
bool checked) {
1196 if (!m_configUi)
return;
1200 m_rep->SetRulerMode(checked ? 1 : 0);
1201 m_rep->BuildRepresentation();
1205 m_configUi->rulerDistanceSpinBox->setEnabled(checked);
1206 m_configUi->numberOfTicksSpinBox->setEnabled(!checked);
1211 void cvDistanceTool::on_rulerDistanceSpinBox_valueChanged(
double value) {
1212 if (!m_configUi)
return;
1216 m_rep->SetRulerDistance(value);
1217 m_rep->BuildRepresentation();
1222 void cvDistanceTool::on_numberOfTicksSpinBox_valueChanged(
int value) {
1223 if (!m_configUi)
return;
1227 m_rep->SetNumberOfRulerTicks(value);
1228 m_rep->BuildRepresentation();
1233 void cvDistanceTool::on_scaleSpinBox_valueChanged(
double value) {
1234 if (!m_configUi)
return;
1238 m_rep->SetScale(value);
1239 m_rep->BuildRepresentation();
1243 updateDistanceDisplay();
1247 void cvDistanceTool::on_labelFormatLineEdit_textChanged(
const QString& text) {
1248 if (!m_configUi)
return;
1251 std::string formatStr = text.toStdString();
1254 if (formatStr.find(
'%') == std::string::npos) {
1256 "[cvDistanceTool] Invalid label format: missing '%' specifier");
1261 m_rep->SetLabelFormat(formatStr.c_str());
1262 m_rep->BuildRepresentation();
1268 void cvDistanceTool::on_widgetVisibilityCheckBox_toggled(
bool checked) {
1269 if (!m_configUi)
return;
1282 void cvDistanceTool::on_labelVisibilityCheckBox_toggled(
bool checked) {
1283 if (!m_configUi)
return;
1287 m_rep->SetShowLabel(checked ? 1 : 0);
1288 m_rep->BuildRepresentation();
1293 void cvDistanceTool::on_lineWidthSpinBox_valueChanged(
double value) {
1294 if (!m_configUi)
return;
1299 if (
auto* prop = m_rep->GetLineProperty()) {
1300 prop->SetLineWidth(value);
1302 m_rep->BuildRepresentation();
1309 if (!vtkWidget)
return;
1318 &cvDistanceTool::pickAlternatingPoint);
1323 QKeySequence(tr(
"Ctrl+P")),
true, vtkWidget);
1328 &cvDistanceTool::pickAlternatingPoint);
1338 &cvDistanceTool::pickKeyboardPoint1);
1343 QKeySequence(tr(
"Ctrl+1")),
true, vtkWidget);
1348 &cvDistanceTool::pickKeyboardPoint1);
1358 &cvDistanceTool::pickKeyboardPoint2);
1363 QKeySequence(tr(
"Ctrl+2")),
true, vtkWidget);
1368 &cvDistanceTool::pickKeyboardPoint2);
1373 QKeySequence(tr(
"N")),
false, vtkWidget,
1379 &cvDistanceTool::pickNormalDirection);
1383 void cvDistanceTool::pickAlternatingPoint(
double x,
double y,
double z) {
1384 if (m_pickPoint1Next) {
1385 pickKeyboardPoint1(
x,
y,
z);
1387 pickKeyboardPoint2(
x,
y,
z);
1389 m_pickPoint1Next = !m_pickPoint1Next;
1392 void cvDistanceTool::pickKeyboardPoint1(
double x,
double y,
double z) {
1393 double pos[3] = {
x,
y,
z};
1397 void cvDistanceTool::pickKeyboardPoint2(
double x,
double y,
double z) {
1398 double pos[3] = {
x,
y,
z};
1402 void cvDistanceTool::pickNormalDirection(
1403 double px,
double py,
double pz,
double nx,
double ny,
double nz) {
1405 double p1[3] = {px,
py, pz};
1409 double p2[3] = {px + nx,
py + ny, pz + nz};
1413 void cvDistanceTool::applyFontProperties() {
1417 if (
auto* axis = m_rep->GetAxisActor()) {
1423 axis->AdjustLabelsOff();
1428 double baseFontSize = 12.0;
1429 double fontFactor =
static_cast<double>(
m_fontSize) / baseFontSize;
1430 if (fontFactor < 0.1) fontFactor = 0.1;
1431 if (fontFactor > 10.0) fontFactor = 10.0;
1434 axis->SetFontFactor(fontFactor);
1435 axis->SetLabelFactor(fontFactor * 0.8);
1439 if (
auto* titleProp = axis->GetTitleTextProperty()) {
1440 titleProp->SetFontFamilyAsString(
m_fontFamily.toUtf8().constData());
1450 titleProp->SetJustificationToLeft();
1452 titleProp->SetJustificationToCentered();
1454 titleProp->SetJustificationToRight();
1458 titleProp->SetVerticalJustificationToTop();
1460 titleProp->SetVerticalJustificationToCentered();
1462 titleProp->SetVerticalJustificationToBottom();
1465 titleProp->Modified();
1469 if (
auto* labelProp = axis->GetLabelTextProperty()) {
1470 labelProp->SetFontFamilyAsString(
m_fontFamily.toUtf8().constData());
1480 labelProp->SetJustificationToLeft();
1482 labelProp->SetJustificationToCentered();
1484 labelProp->SetJustificationToRight();
1488 labelProp->SetVerticalJustificationToTop();
1490 labelProp->SetVerticalJustificationToCentered();
1492 labelProp->SetVerticalJustificationToBottom();
1495 labelProp->Modified();
1503 m_rep->BuildRepresentation();
1505 m_widget->Modified();
float PointCoordinateType
Type of the coordinates of a (N-D) point.
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 Error(const char *format,...)
Display an error dialog with formatted message.
Type norm() const
Returns vector norm.
2D label (typically attached to points)
bool addPickedPoint(ccGenericPointCloud *cloud, unsigned pointIndex, bool entityCenter=false)
Adds a point to this label.
const float * getPosition() const
Returns relative position.
void setCollapsed(bool state)
Whether to collapse label or not.
void setDisplayedIn2D(bool state)
Whether to display the label in 2D.
void setPosition(float x, float y)
Sets relative position.
void displayPointLegend(bool state)
Whether to display the point(s) legend (title only)
virtual void setVisible(bool state)
Sets entity visibility.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
A 3D cloud interface with associated features (color, normals, octree, etc.)
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Hierarchical CLOUDVIEWER Object.
virtual ccBBox getBB_recursive(bool withGLFeatures=false, bool onlyEnabledChildren=true)
Returns the bounding-box of this entity and it's children.
virtual void setEnabled(bool state)
Sets the "enabled" property.
bool isKindOf(CV_CLASS_ENUM type) const
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
Vector3Tpl< T > getDiagVec() const
Returns diagonal vector.
Vector3Tpl< T > getCenter() const
Returns center.
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.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Extended LineRepresentation with distance display and ruler features.
void SetScale(double scale)
Set/Get scale factor.
Handle representation with custom translation axis support.
cvPointPickingHelper is a helper class for supporting keyboard shortcut-based point picking in measur...
@ CoordinatesAndNormal
Pick both coordinates and normal.
void setContextWidget(QWidget *widget)
Set the context widget for the shortcut.
void setInteractor(vtkRenderWindowInteractor *interactor)
Set the VTK interactor for picking.
void setRenderer(vtkRenderer *renderer)
Set the VTK renderer for picking.
void pickNormal(double px, double py, double pz, double nx, double ny, double nz)
Emitted when a point and normal are picked.
void pick(double x, double y, double z)
Emitted when a point is picked.
static double distance(T *pot1, T *pot2)
void vtkInitOnce(T **obj)
Tensor Minimum(const Tensor &input, const Tensor &other)
Computes the element-wise minimum of input and other. The tensors must have same data type and device...