20 #include <vtkAbstractPicker.h>
21 #include <vtkAngleRepresentation2D.h>
22 #include <vtkAxesActor.h>
23 #include <vtkCamera.h>
24 #include <vtkClipPolyData.h>
25 #include <vtkColorTransferFunction.h>
26 #include <vtkConeSource.h>
27 #include <vtkDelaunay2D.h>
28 #include <vtkGenericOpenGLRenderWindow.h>
29 #include <vtkIdFilter.h>
30 #include <vtkImageData.h>
31 #include <vtkLogoRepresentation.h>
32 #include <vtkLogoWidget.h>
33 #include <vtkLookupTable.h>
34 #include <vtkOrientationMarkerWidget.h>
35 #include <vtkPNGReader.h>
36 #include <vtkProperty2D.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkRenderer.h>
39 #include <vtkRendererCollection.h>
40 #include <vtkScalarBarActor.h>
41 #include <vtkScalarBarRepresentation.h>
42 #include <vtkScalarBarWidget.h>
43 #include <vtkTransform.h>
44 #include <vtkVertexGlyphFilter.h>
53 #include <QApplication>
54 #include <QCoreApplication>
55 #include <QHBoxLayout>
57 #include <QMainWindow>
58 #include <QMessageBox>
60 #include <QPushButton>
64 #include <QTouchEvent>
65 #include <QWheelEvent>
76 #define VTK_CREATE(TYPE, NAME) \
77 vtkSmartPointer<TYPE> NAME = vtkSmartPointer<TYPE>::New()
80 class VtkWidgetPrivate {
86 void configRenderer(vtkRenderer* renderer);
91 bool multiViewports =
false;
92 vtkRenderer* defaultRenderer =
nullptr;
96 QList<vtkRenderer*> renderers;
97 QList<vtkProp*> actors;
98 QList<vtkProp*> props;
103 VtkWidgetPrivate::VtkWidgetPrivate(
QVTKWidgetCustom* q) : q_ptr(q) { init(); }
105 VtkWidgetPrivate::~VtkWidgetPrivate() {}
107 void VtkWidgetPrivate::configRenderer(vtkRenderer* renderer) {
108 if (!renderer)
return;
113 renderer->SetBackground(bgclr);
119 if ((cols * cols) >=
count)
return cols;
126 switch (renderers.size()) {
180 : QVTKOpenGLNativeWidget(parentWindow),
184 m_dataObject(nullptr),
185 m_modelActor(nullptr),
186 m_interactor(nullptr),
187 m_logoWidget(nullptr),
188 m_scalarbarWidget(nullptr),
189 m_axesWidget(nullptr),
191 m_wheelZoomUpdateTimer(nullptr) {
192 this->setWindowTitle(
"3D View");
204 QSurfaceFormat
fmt = QVTKOpenGLNativeWidget::defaultFormat();
205 fmt.setStereo(stereoMode);
209 this->setEnableHiDPI(
true);
213 setAcceptDrops(
true);
214 setAttribute(Qt::WA_AcceptTouchEvents,
true);
216 vtkObject::GlobalWarningDisplayOff();
217 d_ptr =
new VtkWidgetPrivate(
this);
234 double min,
double max) {
241 lut->SetHueRange(hsv1[0], hsv2[0]);
242 lut->SetSaturationRange(hsv1[1], hsv2[1]);
243 lut->SetValueRange(hsv1[2], hsv2[2]);
244 lut->SetTableRange(min, max);
267 viewTransform->SetMatrix(viewMat);
269 cam->ApplyTransform(viewTransform);
270 this->
m_render->SetActiveCamera(cam);
277 ProjTransform->Determinant(projMat);
278 this->
m_camera->SetExplicitProjectionTransformMatrix(ProjTransform);
282 return QThread::currentThread() == QCoreApplication::instance()->thread();
290 QMetaObject::invokeMethod(
292 Qt::QueuedConnection);
302 m_render->SetDisplayPoint(input2D.
x, input2D.
y, input2D.
z);
304 const double* world =
m_render->GetWorldPoint();
305 for (
int i = 0; i < 3; i++) {
306 output3D.
u[i] = world[i] / world[3];
317 m_render->SetWorldPoint(worldPos.
x, worldPos.
y, worldPos.
z, 1.0);
319 displayPos.
x = (
m_render->GetDisplayPoint())[0];
320 displayPos.
y = (
m_render->GetDisplayPoint())[1];
321 displayPos.
z = (
m_render->GetDisplayPoint())[2];
331 cam->SetPosition(pos.
x, pos.
y, pos.
z);
332 this->
m_render->SetActiveCamera(cam);
338 cam->SetFocalPoint(pos.
x, pos.
y, pos.
z);
339 this->
m_render->SetActiveCamera(cam);
345 cam->SetViewUp(pos.
x, pos.
y, pos.
z);
346 this->
m_render->SetActiveCamera(cam);
355 m_render->SetGradientBackground(gradient);
359 if (
d_ptr->multiViewports != multi) {
360 d_ptr->multiViewports = multi;
367 if (!actor ||
d_ptr->actors.contains(actor))
return;
372 d_ptr->actors.append(actor);
374 if (!
d_ptr->multiViewports) {
375 if (
d_ptr->renderers.isEmpty()) {
376 vtkRenderer* renderer = vtkRenderer::New();
377 renderer->SetBackground(vtkClr);
378 d_ptr->configRenderer(renderer);
379 renderer->AddActor(actor);
381 d_ptr->renderers.append(renderer);
382 renderer->ResetCamera();
392 vtkRenderer* renderer = vtkRenderer::New();
393 renderer->SetBackground(vtkClr);
394 d_ptr->configRenderer(renderer);
395 renderer->AddActor(actor);
397 d_ptr->renderers.append(renderer);
398 d_ptr->layoutRenderers();
399 renderer->ResetCamera();
405 if (!prop ||
d_ptr->props.contains(prop))
return;
407 d_ptr->props.append(prop);
409 if (!
d_ptr->multiViewports) {
410 if (
d_ptr->renderers.isEmpty()) {
411 vtkRenderer* renderer = vtkRenderer::New();
412 d_ptr->configRenderer(renderer);
413 renderer->AddViewProp(prop);
415 d_ptr->renderers.append(renderer);
416 renderer->ResetCamera();
424 vtkRenderer* renderer = vtkRenderer::New();
425 d_ptr->configRenderer(renderer);
426 renderer->AddViewProp(prop);
428 d_ptr->renderers.append(renderer);
429 d_ptr->layoutRenderers();
430 renderer->ResetCamera();
438 foreach (
auto actor,
d_ptr->actors) actor->SetVisibility(visible);
442 actor->SetVisibility(visible);
446 return actor->GetVisibility();
450 if (
d_ptr->backgroundColor != clr) {
451 d_ptr->backgroundColor = clr;
453 foreach (vtkRenderer* renderer,
d_ptr->renderers)
454 d_ptr->configRenderer(renderer);
458 vtkRenderer* renderer = renderers->GetFirstRenderer();
460 renderer = renderers->GetNextItem();
468 return d_ptr->backgroundColor;
474 if (!
d_ptr->renderers.contains(
d_ptr->defaultRenderer))
475 d_ptr->renderers.append(
d_ptr->defaultRenderer);
476 return d_ptr->defaultRenderer;
480 if (!
d_ptr->defaultRenderer)
return false;
481 return d_ptr->defaultRenderer->GetActors()->GetNumberOfItems() != 0;
486 aa(bounds,
d_ptr->bounds);
513 if ((
event->buttons() & Qt::RightButton)) {
516 ((QApplication::keyboardModifiers() & Qt::ControlModifier) &&
519 QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor));
526 }
else if (
event->buttons() & Qt::LeftButton) {
531 QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
551 QVTKOpenGLNativeWidget::mousePressEvent(
event);
559 const int x =
event->x();
560 const int y =
event->y();
569 QVTKOpenGLNativeWidget::mouseDoubleClickEvent(
event);
573 bool doRedraw =
false;
574 Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
581 if (keyboardModifiers & Qt::AltModifier) {
585 float sizeModifier = (delta < 0.0 ? -1.0f : 1.0f);
591 }
else if (keyboardModifiers & Qt::ControlModifier) {
595 static const int MAX_INCREMENT = 150;
599 std::min(std::max(0, increment + (delta < 0 ? -1 : 1)),
601 if (newIncrement != increment) {
603 newIncrement, MAX_INCREMENT + 1);
610 }
else if (keyboardModifiers & Qt::ShiftModifier) {
615 (delta < 0 ? -1.0f : 1.0f));
616 newFOV = std::min(std::max(1.0f, newFOV), 180.0f);
626 QVTKOpenGLNativeWidget::wheelEvent(
event);
630 float wheelDelta_deg =
static_cast<float>(delta) / 8;
669 (
event->buttons() & Qt::LeftButton) &&
673 QVTKOpenGLNativeWidget::mouseMoveEvent(
event);
679 const int x =
event->x();
680 const int y =
event->y();
692 if (
event->buttons() == Qt::NoButton) {
706 (
x * retinaScale * 3 <
709 &&
y * retinaScale * 2 <
711 areaRect.height() * 4);
725 QString message = QString(
"2D (%1 ; %2)").arg(
x).arg(
y);
727 message += QString(
" --> 3D (%1 ; %2 ; %3)")
745 if ((
event->buttons() & Qt::RightButton)) {
750 if (abs(dx) > 0 || abs(dy) > 0) {
756 }
else if ((
event->buttons() & Qt::MiddleButton)) {
761 CCVector3d u(dx * pixSize, -dy * pixSize, 0.0);
769 bool entityMovingMode =
772 ((QApplication::keyboardModifiers() &
773 Qt::ControlModifier) &&
775 if (entityMovingMode) {
797 static_cast<float>(u.
y),
798 static_cast<float>(u.
z));
814 && (QApplication::keyboardModifiers() == Qt::NoModifier ||
815 QApplication::keyboardModifiers() ==
816 Qt::ControlModifier)) {
828 if (abs(dx) > 0 || abs(dy) > 0) {
838 }
else if (
event->buttons() & Qt::LeftButton)
853 && (QApplication::keyboardModifiers() == Qt::NoModifier ||
854 QApplication::keyboardModifiers() ==
855 Qt::ControlModifier)) {
867 if (abs(dx) > 0 || abs(dy) > 0) {
874 if (abs(dx) > 0 || abs(dy) > 0) {
882 if (abs(dx) > 0 || abs(dy) > 0) {
902 (QApplication::keyboardModifiers() & Qt::AltModifier))) {
936 "[ QVTKWidgetCustom::mouseMoveEvent] Failed to "
937 "create seleciton polyline! Not enough "
973 RotationMode rotationMode = StandardMode;
978 rotationMode = BubbleViewMode;
980 rotationMode = LockedAxisMode;
984 switch (rotationMode) {
985 case BubbleViewMode: {
989 if (std::abs(posDelta.x()) != 0) {
1003 if (std::abs(posDelta.y()) != 0) {
1006 static_cast<double>(
1014 rotMat = rotX * rotMat;
1018 case StandardMode: {
1032 s_lastMouseOrientation,
1033 currentMouseOrientation);
1034 s_lastMouseOrientation = currentMouseOrientation;
1037 case LockedAxisMode: {
1046 bool topView = (std::abs(axis.
z) > 0.5);
1047 double angle_rad = 0.0;
1063 static_cast<double>(
1065 static_cast<double>(
1070 static_cast<double>(
x),
1071 static_cast<double>(
height() -
y), 0.0);
1076 double u_norm = std::abs(
1078 if (u_norm > 1.0e-6) {
1080 u_norm / (
a.norm() * b.
norm());
1084 sin_angle = -sin_angle;
1106 lockedRotationAxis2D.
z = 0;
1109 CCVector3d mouseShift(
static_cast<double>(dx),
1110 -
static_cast<double>(dy),
1113 mouseShift.
dot(lockedRotationAxis2D) *
1114 lockedRotationAxis2D;
1117 angle_rad = 2.0 *
M_PI * mouseShift.
norm() /
1119 if ((lockedRotationAxis2D * mouseShift).z >
1121 angle_rad = -angle_rad;
1151 QApplication::changeOverrideCursor(
1152 QCursor(Qt::ClosedHandCursor));
1169 int x,
int y,
int dx,
int dy,
bool updatePosition) {
1170 if (updatePosition) {
1173 CCVector3d u(dx * pixSize, -dy * pixSize, 0.0);
1180 if (activeItem->move2D(
x * retinaScale,
y * retinaScale,
1181 dx * retinaScale, dy * retinaScale,
1185 }
else if (activeItem->move3D(u)) {
1197 QVTKOpenGLNativeWidget::mouseReleaseEvent(
event);
1209 QApplication::restoreOverrideCursor();
1225 if ((
event->button() == Qt::MiddleButton)) {
1226 if (mouseHasMoved) {
1239 Qt::MiddleButton)) {
1244 }
else if (
event->button() == Qt::LeftButton) {
1245 if (mouseHasMoved) {
1254 int pickX =
static_cast<int>(A->
x + C->
x) / 2;
1255 int pickY =
static_cast<int>(A->
y + C->
y) / 2;
1256 int pickW =
static_cast<int>(std::abs(C->
x - A->
x));
1257 int pickH =
static_cast<int>(std::abs(C->
y - A->
y));
1295 "[QVTKWidgetCustom::mouseReleaseEvent] Skipping "
1297 "picking because VTK widget was clicked");
1304 }
else if (
event->button() == Qt::RightButton) {
1307 if (mouseHasMoved) {
1316 if (mouseHasMoved) {
1324 const QMimeData* mimeData =
event->mimeData();
1325 if (mimeData->hasFormat(
"text/uri-list"))
event->acceptProposedAction();
1327 QVTKOpenGLNativeWidget::dragEnterEvent(
event);
1331 const QMimeData* mimeData =
event->mimeData();
1333 if (mimeData && mimeData->hasFormat(
"text/uri-list")) {
1334 QStringList fileNames;
1335 for (
const QUrl& url : mimeData->urls()) {
1336 QString fileName = url.toLocalFile();
1337 fileNames.append(fileName);
1339 CVLog::Print(QString(
"File dropped: %1").arg(fileName));
1343 if (!fileNames.empty()) {
1347 event->acceptProposedAction();
1350 QVTKOpenGLNativeWidget::dropEvent(
event);
1355 switch (evt->type()) {
1357 case QEvent::TouchBegin:
1358 case QEvent::TouchEnd: {
1359 QTouchEvent* touchEvent =
static_cast<QTouchEvent*
>(evt);
1360 touchEvent->accept();
1369 case QEvent::Close: {
1378 case QEvent::DragEnter: {
1383 case QEvent::Drop: {
1384 dropEvent(
static_cast<QDropEvent*
>(evt));
1388 case QEvent::TouchUpdate: {
1392 QTouchEvent* touchEvent =
static_cast<QTouchEvent*
>(evt);
1393 const QList<QTouchEvent::TouchPoint>& touchPoints =
1394 touchEvent->touchPoints();
1395 if (touchPoints.size() == 2) {
1396 QPointF D = (touchPoints[1].pos() - touchPoints[0].pos());
1397 qreal dist = std::sqrt(D.x() * D.x() + D.y() * D.y());
1410 QSize newSize =
static_cast<QResizeEvent*
>(evt)->
size();
1416 case QEvent::KeyPress: {
1419 QKeyEvent* keyEvent =
static_cast<QKeyEvent*
>(evt);
1420 if (keyEvent->key() == Qt::Key_Escape) {
1422 "[QVTKWidgetCustom] ESC key pressed, forwarding to "
1432 QKeyEvent* newEvent =
1433 new QKeyEvent(QEvent::KeyPress, Qt::Key_Escape,
1434 keyEvent->modifiers());
1435 QCoreApplication::postEvent(
m_win, newEvent);
1453 QVTKOpenGLNativeWidget::keyPressEvent(
event);
Vector2Tpl< int > CCVector2i
Int 2D Vector.
Vector3Tpl< double > CCVector3d
Double 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
double qtCompatWheelEventDelta(const QWheelEvent *event) noexcept
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool PrintVerbose(const char *format,...)
Prints out a verbose formatted message in console.
void normalize()
Sets vector norm to unity.
Type dot(const Vector3Tpl &v) const
Dot product.
Type norm() const
Returns vector norm.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
ccGLMatrixTpl< T > transposed() const
Returns transposed matrix.
void applyRotation(Vector3Tpl< float > &vec) const
Applies rotation only to a 3D vector (in place) - float version.
static ccGLMatrixTpl< double > FromToRotation(const Vector3Tpl< double > &from, const Vector3Tpl< double > &to)
Creates a transformation matrix that rotates a vector to another.
Vector3Tpl< T > getColumnAsVec3D(unsigned index) const
Returns a copy of a given column as a CCVector3.
void initFromParameters(T alpha_rad, const Vector3Tpl< T > &axis3D, const Vector3Tpl< T > &t3D)
Inits transformation from a rotation axis, an angle and a translation.
Double version of ccGLMatrixTpl.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Interactor interface (entity that can be dragged or clicked in a 3D view)
virtual bool acceptClick(int x, int y, Qt::MouseButton button)
Called on mouse click.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
void setForeground(bool state)
Defines if the polyline is drawn in background or foreground.
void set2DMode(bool state)
Defines if the polyline is considered as 2D or 3D.
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPointPersistentPtr(unsigned index)=0
Returns the ith point as a persistent pointer.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
void setClosed(bool state)
Sets whether the polyline is closed or not.
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
double zNearCoef
Theoretical perspective 'zNear' relative position.
static int ZNearCoefToIncrement(double coef, int iMax)
bool perspectiveView
Perspective view state.
float fov_deg
Camera F.O.V. (field of view) in degrees.
static double IncrementToZNearCoef(int i, int iMax)
float cameraAspectRatio
Camera aspect ratio.
double zFar
Actual perspective 'zFar' value.
float defaultPointSize
Point size.
const CCVector3d & getPivotPoint() const
Returns the pivot point (for object-centered view mode)
ccGLMatrixd viewMat
Visualization matrix (rotation only)
void vtkColor(const QColor &clr, double *vtkClr)
void qColor2HSV(const QColor &clr, double *hsv)
void layoutRenderers< 7 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 5 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 8 >(const QList< vtkRenderer * > &renderers)
void vtkInitOnce(T **obj)
void layoutRenderers< 10 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 1 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 4 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 3 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 9 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 2 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 6 >(const QList< vtkRenderer * > &renderers)
void Resize(const core::Tensor &src_im, core::Tensor &dst_im, Image::InterpType interp_type)
float RadiansToDegrees(int radians)
Convert radians to degrees.
float DegreesToRadians(int degrees)
Convert degrees to radians.
constexpr Rgb black(0, 0, 0)
constexpr Rgb green(0, MAX, 0)
OpenGL camera parameters.
ccGLMatrixd modelViewMat
Model view matrix (GL_MODELVIEW)
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)