18 #include <Qt3DCore/QTransform>
19 #include <Qt3DRender/QAttribute>
20 #include <Qt3DExtras/QCylinderMesh>
21 #include <Qt3DExtras/QPhongMaterial>
22 #include <Qt3DExtras/QConeMesh>
23 #include <Qt3DRender/qcameralens.h>
24 #include <Qt3DRender/QCameraSelector>
25 #include <Qt3DRender/QClearBuffers>
26 #include <Qt3DRender/QLayer>
27 #include <Qt3DRender/QLayerFilter>
28 #include <Qt3DRender/QPointLight>
30 #include <QFontDatabase>
41 Qt3DCore::QEntity *parent3DScene,
45 : QObject( parentWindow )
47 , mParentWindow( parentWindow )
48 , mMapScene( mapScene )
49 , mCameraController( cameraCtrl )
52 mAxisViewport = constructAxisViewport( parent3DScene );
53 mAxisViewport->setParent( mParentWindow->activeFrameGraph() );
55 mTwoDLabelViewport = constructLabelViewport( parent3DScene, QRectF( 0.0f, 0.0f, 1.0f, 1.0f ) );
56 mTwoDLabelViewport->setParent( mParentWindow->activeFrameGraph() );
63 connect( mParentWindow, &Qt3DExtras::Qt3DWindow::widthChanged,
this, &Qgs3DAxis::onAxisViewportSizeUpdate );
64 connect( mParentWindow, &Qt3DExtras::Qt3DWindow::heightChanged,
this, &Qgs3DAxis::onAxisViewportSizeUpdate );
66 onAxisViewportSizeUpdate();
71 connect( mMenu, &QMenu::aboutToShow,
this, &Qgs3DAxis::populateMenu );
73 init3DObjectPicking();
82 void Qgs3DAxis::init3DObjectPicking( )
88 mScreenRayCaster =
new Qt3DRender::QScreenRayCaster( mAxisSceneEntity );
89 mScreenRayCaster->addLayer( mAxisSceneLayer );
90 mScreenRayCaster->setFilterMode( Qt3DRender::QScreenRayCaster::AcceptAllMatchingLayers );
91 mScreenRayCaster->setRunMode( Qt3DRender::QAbstractRayCaster::SingleShot );
92 mAxisSceneEntity->addComponent( mScreenRayCaster );
93 QObject::connect( mScreenRayCaster, &Qt3DRender::QScreenRayCaster::hitsChanged,
this, &Qgs3DAxis::onTouchedByRay );
96 mParentWindow->installEventFilter(
this );
99 bool Qgs3DAxis::eventFilter( QObject *watched, QEvent *event )
101 if ( watched != mParentWindow )
105 if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseMove )
107 QMouseEvent *lastClickEvent =
static_cast<QMouseEvent *
>( event );
109 QPointF normalizedPos( (
float )lastClickEvent->pos().x() / mParentWindow->width(),
110 (
float )lastClickEvent->pos().y() / mParentWindow->height() );
112 if ( event->type() == QEvent::MouseButtonRelease )
113 qDebug() <<
"normalized pos:" << normalizedPos <<
"/ viewport:" << mAxisViewport->normalizedRect();
116 if ( mAxisViewport->normalizedRect().contains( normalizedPos ) )
118 mLastClickedButton = lastClickEvent->button();
119 mLastClickedPos = lastClickEvent->pos();
122 mScreenRayCaster->trigger( mLastClickedPos );
126 else if ( mPreviousCursor != Qt::ArrowCursor && mParentWindow->cursor() == Qt::ArrowCursor )
128 mParentWindow->setCursor( mPreviousCursor );
129 mPreviousCursor = Qt::ArrowCursor;
136 void Qgs3DAxis::onTouchedByRay(
const Qt3DRender::QAbstractRayCaster::Hits &hits )
142 qDebug() << hits.length() <<
"hit(s) at " << mLastClickedPos <<
"with" << mLastClickedButton;
143 for (
int i = 0; i < hits.length(); ++i )
145 qDebug() <<
"\tHit Type: " << hits.at( i ).type();
146 qDebug() <<
"\tHit triangle id: " << hits.at( i ).primitiveIndex();
147 qDebug() <<
"\tHit distance: " << hits.at( i ).distance();
148 qDebug() <<
"\tHit entity name: " << hits.at( i ).entity()->objectName();
152 for (
int i = 0; i < hits.length() && mHitsFound == -1; ++i )
154 if ( hits.at( i ).distance() < 500.0 && ( hits.at( i ).entity() == mCubeRoot || hits.at( i ).entity() == mAxisRoot || hits.at( i ).entity()->parent() == mCubeRoot || hits.at( i ).entity()->parent() == mAxisRoot ) )
161 if ( mLastClickedButton == Qt::NoButton )
163 if ( mHitsFound != -1 )
165 if ( mParentWindow->cursor() != Qt::ArrowCursor )
167 mPreviousCursor = mParentWindow->cursor();
168 mParentWindow->setCursor( Qt::ArrowCursor );
172 else if ( mLastClickedButton == Qt::MouseButton::RightButton && mHitsFound != -1 )
174 displayMenuAt( mLastClickedPos );
176 else if ( mLastClickedButton == Qt::MouseButton::LeftButton )
178 if ( mMenu->isVisible() )
181 if ( mHitsFound != -1 )
183 if ( hits.at( mHitsFound ).entity() == mCubeRoot || hits.at( mHitsFound ).entity()->parent() == mCubeRoot )
186 switch ( hits.at( mHitsFound ).primitiveIndex() / 2 )
189 qDebug() <<
"East face";
193 qDebug() <<
"West face ";
197 qDebug() <<
"North face ";
201 qDebug() <<
"South face";
205 qDebug() <<
"Top face ";
209 qDebug() <<
"Bottom face ";
213 switch ( hits.at( mHitsFound ).primitiveIndex() / 2 )
216 onCameraViewChangeEast();
220 onCameraViewChangeWest();
224 onCameraViewChangeNorth();
228 onCameraViewChangeSouth();
232 onCameraViewChangeTop();
236 onCameraViewChangeBottom();
243 mParentWindow->requestUpdate();
249 Qt3DRender::QViewport *Qgs3DAxis::constructAxisViewport( Qt3DCore::QEntity *parent3DScene )
251 Qt3DRender::QViewport *axisViewport =
new Qt3DRender::QViewport;
255 mAxisSceneLayer =
new Qt3DRender::QLayer;
257 mAxisSceneEntity =
new Qt3DCore::QEntity;
258 mAxisSceneEntity->setParent( parent3DScene );
259 mAxisSceneEntity->setObjectName(
"3DAxis_SceneEntity" );
261 mAxisCamera =
new Qt3DRender::QCamera;
262 mAxisCamera->setParent( mAxisSceneEntity );
263 mAxisCamera->setProjectionType( mCameraController->
camera()->projectionType() );
264 mAxisCamera->lens()->setFieldOfView( mCameraController->
camera()->lens()->fieldOfView() * 0.5 );
266 mAxisCamera->setUpVector( QVector3D( 0.0f, 0.0f, 1.0f ) );
267 mAxisCamera->setViewCenter( QVector3D( 0.0f, 0.0f, 0.0f ) );
270 Qt3DRender::QLayer *axisLayer =
new Qt3DRender::QLayer;
271 axisLayer->setRecursive(
true );
272 mAxisSceneEntity->addComponent( axisLayer );
274 Qt3DRender::QLayerFilter *axisLayerFilter =
new Qt3DRender::QLayerFilter( axisViewport );
275 axisLayerFilter->addLayer( axisLayer );
277 Qt3DRender::QCameraSelector *axisCameraSelector =
new Qt3DRender::QCameraSelector;
278 axisCameraSelector->setParent( axisLayerFilter );
279 axisCameraSelector->setCamera( mAxisCamera );
281 Qt3DRender::QClearBuffers *clearBuffers =
new Qt3DRender::QClearBuffers( axisCameraSelector );
282 clearBuffers->setBuffers( Qt3DRender::QClearBuffers::DepthBuffer );
288 Qt3DRender::QViewport *Qgs3DAxis::constructLabelViewport( Qt3DCore::QEntity *parent3DScene,
const QRectF &parentViewportSize )
290 Qt3DRender::QViewport *twoDViewport =
new Qt3DRender::QViewport;
292 twoDViewport->setNormalizedRect( parentViewportSize );
294 mTwoDLabelSceneEntity =
new Qt3DCore::QEntity;
295 mTwoDLabelSceneEntity->setParent( parent3DScene );
296 mTwoDLabelSceneEntity->setEnabled(
true );
298 mTwoDLabelCamera =
new Qt3DRender::QCamera;
299 mTwoDLabelCamera->setParent( mTwoDLabelSceneEntity );
300 mTwoDLabelCamera->setProjectionType( Qt3DRender::QCameraLens::ProjectionType::OrthographicProjection );
301 mTwoDLabelCamera->lens()->setOrthographicProjection(
302 -mParentWindow->width() / 2.0f, mParentWindow->width() / 2.0f,
303 -mParentWindow->height() / 2.0f, mParentWindow->height() / 2.0f,
306 mTwoDLabelCamera->setUpVector( QVector3D( 0.0f, 0.0f, 1.0f ) );
307 mTwoDLabelCamera->setViewCenter( QVector3D( 0.0f, 0.0f, 0.0f ) );
309 mTwoDLabelCamera->setPosition( QVector3D( 0.0f, 0.0f, 100.0f ) );
311 Qt3DRender::QLayer *twoDLayer =
new Qt3DRender::QLayer;
312 twoDLayer->setRecursive(
true );
313 mTwoDLabelSceneEntity->addComponent( twoDLayer );
315 Qt3DRender::QLayerFilter *twoDLayerFilter =
new Qt3DRender::QLayerFilter( twoDViewport );
316 twoDLayerFilter->addLayer( twoDLayer );
318 Qt3DRender::QCameraSelector *twoDCameraSelector =
new Qt3DRender::QCameraSelector;
319 twoDCameraSelector->setParent( twoDLayerFilter );
320 twoDCameraSelector->setCamera( mTwoDLabelCamera );
322 Qt3DRender::QClearBuffers *clearBuffers =
new Qt3DRender::QClearBuffers( twoDCameraSelector );
323 clearBuffers->setBuffers( Qt3DRender::QClearBuffers::DepthBuffer );
330 Qt3DRender::QCamera *sourceCamera, Qt3DRender::QViewport *sourceViewport,
331 Qt3DRender::QCamera *destCamera, Qt3DRender::QViewport *destViewport,
332 const QSize &destSize )
334 QVector3D destPos = sourcePos.project( sourceCamera->viewMatrix(),
335 destCamera->projectionMatrix(),
337 destViewport->normalizedRect().width() * destSize.width(),
338 destViewport->normalizedRect().height() * destSize.height() ) );
339 QPointF axisCenter = sourceViewport->normalizedRect().center();
340 QPointF labelCenter = destViewport->normalizedRect().center();
341 QVector3D viewTranslation = QVector3D( ( axisCenter - labelCenter ).x() * destSize.width(),
342 ( axisCenter - labelCenter ).y() * destSize.height(),
344 destPos -= QVector3D( labelCenter.x() * destSize.width(),
345 labelCenter.y() * destSize.height(),
347 destPos.setX( destPos.x() + viewTranslation.x() );
348 destPos.setY( destPos.y() - viewTranslation.y() );
349 destPos.setZ( 0.0f );
352 qDebug() <<
"from3dTo2dLabelPosition: sourcePos" << sourcePos <<
" with" << viewTranslation <<
"corrected destPos" << destPos;
357 void Qgs3DAxis::setEnableCube(
bool show )
359 mCubeRoot->setEnabled( show );
362 void Qgs3DAxis::setEnableAxis(
bool show )
364 mAxisRoot->setEnabled( show );
365 mTextX->setEnabled( show );
366 mTextY->setEnabled( show );
367 mTextZ->setEnabled( show );
370 void Qgs3DAxis::createAxisScene()
372 if ( mAxisRoot ==
nullptr || mCubeRoot ==
nullptr )
375 qDebug() <<
"Should recreate mAxisRoot" << mMode;
377 mAxisRoot =
new Qt3DCore::QEntity;
378 mAxisRoot->setParent( mAxisSceneEntity );
379 mAxisRoot->setObjectName(
"3DAxis_AxisRoot" );
380 mAxisRoot->addComponent( mAxisSceneLayer );
382 createAxis( Qt::Axis::XAxis );
383 createAxis( Qt::Axis::YAxis );
384 createAxis( Qt::Axis::ZAxis );
386 mCubeRoot =
new Qt3DCore::QEntity;
387 mCubeRoot->setParent( mAxisSceneEntity );
388 mCubeRoot->setObjectName(
"3DAxis_CubeRoot" );
389 mCubeRoot->addComponent( mAxisSceneLayer );
396 mAxisSceneEntity->setEnabled(
false );
397 setEnableAxis(
false );
398 setEnableCube(
false );
402 mAxisSceneEntity->setEnabled(
true );
405 setEnableCube(
false );
406 setEnableAxis(
true );
408 const QList< Qgis::CrsAxisDirection > axisDirections = mCrs.
axisOrdering();
410 if ( axisDirections.length() > 0 )
413 mTextY->setText(
"X?" );
415 if ( axisDirections.length() > 1 )
418 mTextY->setText(
"Y?" );
420 if ( axisDirections.length() > 2 )
423 mTextZ->setText( QStringLiteral(
"up" ) );
427 setEnableCube(
true );
428 setEnableAxis(
false );
432 setEnableCube(
false );
433 setEnableAxis(
true );
434 mTextX->setText(
"X?" );
435 mTextY->setText(
"Y?" );
436 mTextZ->setText(
"Z?" );
439 updateAxisLabelPosition();
443 void Qgs3DAxis::populateMenu()
448 QAction *typeOffAct =
new QAction( tr(
"&Off" ), mMenu );
449 typeOffAct->setCheckable(
true );
450 typeOffAct->setStatusTip( tr(
"Disable 3D axis" ) );
452 typeOffAct->setChecked(
true );
454 QAction *typeCrsAct =
new QAction( tr(
"Coordinate Reference &System" ), mMenu );
455 typeCrsAct->setCheckable(
true );
456 typeCrsAct->setStatusTip( tr(
"Coordinate Reference System 3D axis" ) );
458 typeCrsAct->setChecked(
true );
460 QAction *typeCubeAct =
new QAction( tr(
"&Cube" ), mMenu );
461 typeCubeAct->setCheckable(
true );
462 typeCubeAct->setStatusTip( tr(
"Cube 3D axis" ) );
464 typeCubeAct->setChecked(
true );
466 QActionGroup *typeGroup =
new QActionGroup( mMenu );
467 typeGroup->addAction( typeOffAct );
468 typeGroup->addAction( typeCrsAct );
469 typeGroup->addAction( typeCubeAct );
471 connect( typeOffAct, &QAction::triggered,
this, [
this](
bool ) {onAxisModeChanged(
Mode::Off );} );
472 connect( typeCrsAct, &QAction::triggered,
this, [
this](
bool ) {onAxisModeChanged(
Mode::Crs );} );
473 connect( typeCubeAct, &QAction::triggered,
this, [
this](
bool ) {onAxisModeChanged(
Mode::Cube );} );
475 QMenu *typeMenu =
new QMenu( QStringLiteral(
"Axis Type" ), mMenu );
476 typeMenu->addAction( typeOffAct );
477 typeMenu->addAction( typeCrsAct );
478 typeMenu->addAction( typeCubeAct );
479 mMenu->addMenu( typeMenu );
482 QAction *hPosLeftAct =
new QAction( tr(
"&Left" ), mMenu );
483 hPosLeftAct->setCheckable(
true );
484 if ( mAxisViewportHorizPos == Qt::AnchorPoint::AnchorLeft )
485 hPosLeftAct->setChecked(
true );
487 QAction *hPosMiddleAct =
new QAction( tr(
"&Center" ), mMenu );
488 hPosMiddleAct->setCheckable(
true );
489 if ( mAxisViewportHorizPos == Qt::AnchorPoint::AnchorHorizontalCenter )
490 hPosMiddleAct->setChecked(
true );
492 QAction *hPosRightAct =
new QAction( tr(
"&Right" ), mMenu );
493 hPosRightAct->setCheckable(
true );
494 if ( mAxisViewportHorizPos == Qt::AnchorPoint::AnchorRight )
495 hPosRightAct->setChecked(
true );
497 QActionGroup *hPosGroup =
new QActionGroup( mMenu );
498 hPosGroup->addAction( hPosLeftAct );
499 hPosGroup->addAction( hPosMiddleAct );
500 hPosGroup->addAction( hPosRightAct );
502 connect( hPosLeftAct, &QAction::triggered,
this, [
this](
bool ) {onAxisHorizPositionChanged( Qt::AnchorPoint::AnchorLeft );} );
503 connect( hPosMiddleAct, &QAction::triggered,
this, [
this](
bool ) {onAxisHorizPositionChanged( Qt::AnchorPoint::AnchorHorizontalCenter );} );
504 connect( hPosRightAct, &QAction::triggered,
this, [
this](
bool ) {onAxisHorizPositionChanged( Qt::AnchorPoint::AnchorRight );} );
506 QMenu *horizPosMenu =
new QMenu( QStringLiteral(
"Horizontal Position" ), mMenu );
507 horizPosMenu->addAction( hPosLeftAct );
508 horizPosMenu->addAction( hPosMiddleAct );
509 horizPosMenu->addAction( hPosRightAct );
510 mMenu->addMenu( horizPosMenu );
513 QAction *vPosTopAct =
new QAction( tr(
"&Top" ), mMenu );
514 vPosTopAct->setCheckable(
true );
515 if ( mAxisViewportVertPos == Qt::AnchorPoint::AnchorTop )
516 vPosTopAct->setChecked(
true );
518 QAction *vPosMiddleAct =
new QAction( tr(
"&Middle" ), mMenu );
519 vPosMiddleAct->setCheckable(
true );
520 if ( mAxisViewportVertPos == Qt::AnchorPoint::AnchorVerticalCenter )
521 vPosMiddleAct->setChecked(
true );
523 QAction *vPosBottomAct =
new QAction( tr(
"&Bottom" ), mMenu );
524 vPosBottomAct->setCheckable(
true );
525 if ( mAxisViewportVertPos == Qt::AnchorPoint::AnchorBottom )
526 vPosBottomAct->setChecked(
true );
528 QActionGroup *vPosGroup =
new QActionGroup( mMenu );
529 vPosGroup->addAction( vPosTopAct );
530 vPosGroup->addAction( vPosMiddleAct );
531 vPosGroup->addAction( vPosBottomAct );
533 connect( vPosTopAct, &QAction::triggered,
this, [
this](
bool ) {onAxisVertPositionChanged( Qt::AnchorPoint::AnchorTop );} );
534 connect( vPosMiddleAct, &QAction::triggered,
this, [
this](
bool ) {onAxisVertPositionChanged( Qt::AnchorPoint::AnchorVerticalCenter );} );
535 connect( vPosBottomAct, &QAction::triggered,
this, [
this](
bool ) {onAxisVertPositionChanged( Qt::AnchorPoint::AnchorBottom );} );
537 QMenu *vertPosMenu =
new QMenu( QStringLiteral(
"Vertical Position" ), mMenu );
538 vertPosMenu->addAction( vPosTopAct );
539 vertPosMenu->addAction( vPosMiddleAct );
540 vertPosMenu->addAction( vPosBottomAct );
541 mMenu->addMenu( vertPosMenu );
544 QAction *viewHomeAct =
new QAction( tr(
"&Home" ) +
"\t Ctrl+1", mMenu );
545 QAction *viewTopAct =
new QAction( tr(
"&Top" ) +
"\t Ctrl+5", mMenu );
546 QAction *viewNorthAct =
new QAction( tr(
"&North" ) +
"\t Ctrl+8", mMenu );
547 QAction *viewEastAct =
new QAction( tr(
"&East" ) +
"\t Ctrl+6", mMenu );
548 QAction *viewSouthAct =
new QAction( tr(
"&South" ) +
"\t Ctrl+2", mMenu );
549 QAction *viewWestAct =
new QAction( tr(
"&West" ) +
"\t Ctrl+4", mMenu );
550 QAction *viewBottomAct =
new QAction( tr(
"&Bottom" ), mMenu );
552 connect( viewHomeAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeHome );
553 connect( viewTopAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeTop );
554 connect( viewNorthAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeNorth );
555 connect( viewEastAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeEast );
556 connect( viewSouthAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeSouth );
557 connect( viewWestAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeWest );
558 connect( viewBottomAct, &QAction::triggered,
this, &Qgs3DAxis::onCameraViewChangeBottom );
563 QWidget *mapCanvas =
dynamic_cast<QWidget *
>( eng->parent() );
564 if ( mapCanvas ==
nullptr )
565 qDebug() <<
"NO CANVAS!";
568 QShortcut *shortcutHome =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_1 ), mapCanvas );
569 connect( shortcutHome, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeHome();} );
571 QShortcut *shortcutTop =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_5 ), mapCanvas );
572 connect( shortcutTop, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeTop();} );
574 QShortcut *shortcutNorth =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_8 ), mapCanvas );
575 connect( shortcutNorth, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeNorth();} );
577 QShortcut *shortcutEast =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_6 ), mapCanvas );
578 connect( shortcutEast, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeEast();} );
580 QShortcut *shortcutSouth =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_2 ), mapCanvas );
581 connect( shortcutSouth, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeSouth();} );
583 QShortcut *shortcutWest =
new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_4 ), mapCanvas );
584 connect( shortcutWest, &QShortcut::activated,
this, [
this]( ) {onCameraViewChangeWest();} );
588 QMenu *viewMenu =
new QMenu( QStringLiteral(
"Camera View" ), mMenu );
589 viewMenu->addAction( viewHomeAct );
590 viewMenu->addAction( viewTopAct );
591 viewMenu->addAction( viewNorthAct );
592 viewMenu->addAction( viewEastAct );
593 viewMenu->addAction( viewSouthAct );
594 viewMenu->addAction( viewWestAct );
595 viewMenu->addAction( viewBottomAct );
596 mMenu->addMenu( viewMenu );
599 void Qgs3DAxis::hideMenu()
604 void Qgs3DAxis::displayMenuAt(
const QPoint &sourcePos )
606 mMenu->popup( mParentWindow->parent()->mapToGlobal( sourcePos ) );
617 void Qgs3DAxis::onAxisHorizPositionChanged( Qt::AnchorPoint pos )
625 void Qgs3DAxis::onAxisVertPositionChanged( Qt::AnchorPoint pos )
633 void Qgs3DAxis::onCameraViewChange(
float pitch,
float yaw )
639 pos.
set( pos.
x(), 0.0, pos.
z() );
646 void Qgs3DAxis::createCube( )
648 QVector3D minPos = QVector3D( -mCylinderLength * 0.5f, -mCylinderLength * 0.5f, -mCylinderLength * 0.5f );
651 Qt3DCore::QEntity *cubeLineEntity =
new Qt3DCore::QEntity( mCubeRoot );
652 cubeLineEntity->setObjectName(
"3DAxis_cubeline" );
654 QgsAABB box =
QgsAABB( -mCylinderLength * 0.5f, -mCylinderLength * 0.5f, -mCylinderLength * 0.5f,
655 mCylinderLength * 0.5f, mCylinderLength * 0.5f, mCylinderLength * 0.5f );
657 cubeLineEntity->addComponent( cubeLine );
659 Qt3DExtras::QPhongMaterial *cubeLineMaterial =
new Qt3DExtras::QPhongMaterial;
660 cubeLineMaterial->setAmbient( Qt::white );
661 cubeLineEntity->addComponent( cubeLineMaterial );
664 Qt3DExtras::QCuboidMesh *cubeMesh =
new Qt3DExtras::QCuboidMesh;
665 cubeMesh->setObjectName(
"3DAxis_cubemesh" );
666 cubeMesh->setXExtent( mCylinderLength );
667 cubeMesh->setYExtent( mCylinderLength );
668 cubeMesh->setZExtent( mCylinderLength );
669 mCubeRoot->addComponent( cubeMesh );
671 Qt3DExtras::QPhongMaterial *cubeMaterial =
new Qt3DExtras::QPhongMaterial( mCubeRoot );
672 cubeMaterial->setAmbient( QColor( 100, 100, 100, 50 ) );
673 cubeMaterial->setShininess( 100 );
674 mCubeRoot->addComponent( cubeMaterial );
676 Qt3DCore::QTransform *cubeTransform =
new Qt3DCore::QTransform;
677 QMatrix4x4 transformMatrixcube;
679 transformMatrixcube.translate( minPos + QVector3D( mCylinderLength * 0.5f, mCylinderLength * 0.5f, mCylinderLength * 0.5f ) );
680 cubeTransform->setMatrix( transformMatrixcube );
681 mCubeRoot->addComponent( cubeTransform );
685 int fontSize = 0.75 * mFontSize;
686 float textHeight = fontSize * 1.5;
688 QFont f = QFontDatabase::systemFont( QFontDatabase::FixedFont );
689 f.setPointSize( fontSize );
690 f.setWeight( QFont::Weight::Black );
693 text = QStringLiteral(
"top" );
694 textWidth = text.length() * fontSize * 0.75;
695 QVector3D translation = minPos + QVector3D(
696 mCylinderLength * 0.5f - textWidth / 2.0f,
697 mCylinderLength * 0.5f - textHeight / 2.0f,
698 mCylinderLength * 1.01f );
700 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
704 text = QStringLiteral(
"btm" );
705 textWidth = text.length() * fontSize * 0.75;
706 QVector3D translation = minPos + QVector3D(
707 mCylinderLength * 0.5f - textWidth / 2.0f,
708 mCylinderLength * 0.5f + textHeight / 2.0f,
709 -mCylinderLength * 0.01f );
711 rotation.rotate( 180.0f, QVector3D( 1.0, 0.0, 0.0 ).normalized() );
712 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
716 text = QStringLiteral(
"west" );
717 textWidth = text.length() * fontSize * 0.75;
718 QVector3D translation = minPos + QVector3D(
719 - mCylinderLength * 0.01f,
720 mCylinderLength * 0.5f + textWidth / 2.0f,
721 mCylinderLength * 0.5f - textHeight / 2.0f );
723 rotation.rotate( 90.0f, QVector3D( 0.0, -1.0, 0.0 ).normalized() );
724 rotation.rotate( 90.0f, QVector3D( 0.0, 0.0, -1.0 ).normalized() );
725 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
729 text = QStringLiteral(
"east" );
730 textWidth = text.length() * fontSize * 0.75;
731 QVector3D translation = minPos + QVector3D(
732 mCylinderLength * 1.01f,
733 mCylinderLength * 0.5f - textWidth / 2.0f,
734 mCylinderLength * 0.5f - textHeight / 2.0f );
736 rotation.rotate( 90.0f, QVector3D( 0.0, 1.0, 0.0 ).normalized() );
737 rotation.rotate( 90.0f, QVector3D( 0.0, 0.0, 1.0 ).normalized() );
738 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
742 text = QStringLiteral(
"south" );
743 textWidth = text.length() * fontSize * 0.75;
744 QVector3D translation = minPos + QVector3D(
745 mCylinderLength * 0.5f - textWidth / 2.0f,
746 - mCylinderLength * 0.01f,
747 mCylinderLength * 0.5f - textHeight / 2.0f );
749 rotation.rotate( 90.0f, QVector3D( 1.0, 0.0, 0.0 ).normalized() );
750 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
754 text = QStringLiteral(
"north" );
755 textWidth = text.length() * fontSize * 0.75;
756 QVector3D translation = minPos + QVector3D(
757 mCylinderLength * 0.5f + textWidth / 2.0f,
758 mCylinderLength * 1.01f,
759 mCylinderLength * 0.5f - textHeight / 2.0f );
761 rotation.rotate( 90.0f, QVector3D( -1.0, 0.0, 0.0 ).normalized() );
762 rotation.rotate( 180.0f, QVector3D( 0.0, 0.0, 1.0 ).normalized() );
763 mCubeLabels << addCubeText( text, textHeight, textWidth, f, rotation, translation );
766 for ( Qt3DExtras::QText2DEntity *l : std::as_const( mCubeLabels ) )
768 l->setParent( mCubeRoot );
772 Qt3DExtras::QText2DEntity *Qgs3DAxis::addCubeText(
const QString &text,
float textHeight,
float textWidth,
const QFont &f,
const QMatrix4x4 &rotation,
const QVector3D &translation )
774 Qt3DExtras::QText2DEntity *textEntity =
new Qt3DExtras::QText2DEntity;
775 textEntity->setObjectName(
"3DAxis_cube_label_" + text );
776 textEntity->setFont( f );
777 textEntity->setHeight( textHeight );
778 textEntity->setWidth( textWidth );
779 textEntity->setColor( QColor( 192, 192, 192 ) );
780 textEntity->setText( text );
782 Qt3DCore::QTransform *textFrontTransform =
new Qt3DCore::QTransform();
783 textFrontTransform->setMatrix( rotation );
784 textFrontTransform->setTranslation( translation );
785 textEntity->addComponent( textFrontTransform );
790 void Qgs3DAxis::createAxis( Qt::Axis axisType )
792 float cylinderRadius = 0.05 * mCylinderLength;
793 float coneLength = 0.3 * mCylinderLength;
794 float coneBottomRadius = 0.1 * mCylinderLength;
796 QQuaternion rotation;
799 Qt3DExtras::QText2DEntity *text =
nullptr;
800 Qt3DCore::QTransform *textTransform =
nullptr;
805 case Qt::Axis::XAxis:
806 mTextX =
new Qt3DExtras::QText2DEntity( );
807 mTextX->setParent( mTwoDLabelSceneEntity );
808 connect( mTextX, &Qt3DExtras::QText2DEntity::textChanged,
this, [
this](
const QString & text )
810 mTextX->setWidth( mFontSize * text.length() );
812 mTextTransformX =
new Qt3DCore::QTransform();
813 mTextCoordX = QVector3D( mCylinderLength + coneLength / 2.0, 0.0f, 0.0f );
815 rotation = QQuaternion::fromAxisAndAngle( QVector3D( 0.0f, 0.0f, 1.0f ), -90.0f );
818 textTransform = mTextTransformX;
819 name =
"3DAxis_axisX";
822 case Qt::Axis::YAxis:
823 mTextY =
new Qt3DExtras::QText2DEntity( );
824 mTextY->setParent( mTwoDLabelSceneEntity );
825 connect( mTextY, &Qt3DExtras::QText2DEntity::textChanged,
this, [
this](
const QString & text )
827 mTextY->setWidth( mFontSize * text.length() );
829 mTextTransformY =
new Qt3DCore::QTransform();
830 mTextCoordY = QVector3D( 0.0f, mCylinderLength + coneLength / 2.0, 0.0f );
832 rotation = QQuaternion::fromAxisAndAngle( QVector3D( 0.0f, 0.0f, 0.0f ), 0.0f );
835 textTransform = mTextTransformY;
836 name =
"3DAxis_axisY";
839 case Qt::Axis::ZAxis:
840 mTextZ =
new Qt3DExtras::QText2DEntity( );
841 mTextZ->setParent( mTwoDLabelSceneEntity );
842 connect( mTextZ, &Qt3DExtras::QText2DEntity::textChanged,
this, [
this](
const QString & text )
844 mTextZ->setWidth( mFontSize * text.length() );
846 mTextTransformZ =
new Qt3DCore::QTransform();
847 mTextCoordZ = QVector3D( 0.0f, 0.0f, mCylinderLength + coneLength / 2.0 );
849 rotation = QQuaternion::fromAxisAndAngle( QVector3D( 1.0f, 0.0f, 0.0f ), 90.0f );
852 textTransform = mTextTransformZ;
853 name =
"3DAxis_axisZ";
861 Qt3DCore::QEntity *cylinder =
new Qt3DCore::QEntity( mAxisRoot );
862 cylinder->setObjectName( name );
864 Qt3DExtras::QCylinderMesh *cylinderMesh =
new Qt3DExtras::QCylinderMesh;
865 cylinderMesh->setRadius( cylinderRadius );
866 cylinderMesh->setLength( mCylinderLength );
867 cylinderMesh->setRings( 10 );
868 cylinderMesh->setSlices( 4 );
869 cylinder->addComponent( cylinderMesh );
871 Qt3DExtras::QPhongMaterial *cylinderMaterial =
new Qt3DExtras::QPhongMaterial( cylinder );
872 cylinderMaterial->setAmbient( color );
873 cylinderMaterial->setShininess( 0 );
874 cylinder->addComponent( cylinderMaterial );
876 Qt3DCore::QTransform *cylinderTransform =
new Qt3DCore::QTransform;
877 QMatrix4x4 transformMatrixCylinder;
878 transformMatrixCylinder.rotate( rotation );
879 transformMatrixCylinder.translate( QVector3D( 0.0f, mCylinderLength / 2.0f, 0.0f ) );
880 cylinderTransform->setMatrix( transformMatrixCylinder );
881 cylinder->addComponent( cylinderTransform );
884 Qt3DCore::QEntity *coneEntity =
new Qt3DCore::QEntity( mAxisRoot );
885 coneEntity->setObjectName( name );
886 Qt3DExtras::QConeMesh *coneMesh =
new Qt3DExtras::QConeMesh;
887 coneMesh->setLength( coneLength );
888 coneMesh->setBottomRadius( coneBottomRadius );
889 coneMesh->setTopRadius( 0.0f );
890 coneMesh->setRings( 10 );
891 coneMesh->setSlices( 4 );
892 coneEntity->addComponent( coneMesh );
894 Qt3DExtras::QPhongMaterial *coneMaterial =
new Qt3DExtras::QPhongMaterial( coneEntity );
895 coneMaterial->setAmbient( color );
896 coneMaterial->setShininess( 0 );
897 coneEntity->addComponent( coneMaterial );
899 Qt3DCore::QTransform *coneTransform =
new Qt3DCore::QTransform;
900 QMatrix4x4 transformMatrixCone;
901 transformMatrixCone.rotate( rotation );
902 transformMatrixCone.translate( QVector3D( 0.0f, mCylinderLength, 0.0f ) );
903 coneTransform->setMatrix( transformMatrixCone );
904 coneEntity->addComponent( coneTransform );
907 QFont f = QFont(
"monospace", mFontSize );
908 f.setWeight( QFont::Weight::Black );
909 f.setStyleStrategy( QFont::StyleStrategy::ForceOutline );
911 text->setHeight( mFontSize * 1.5 );
912 text->setWidth( mFontSize );
913 text->setColor( QColor( 192, 192, 192, 192 ) );
914 text->addComponent( textTransform );
921 mAxisViewportVertPos = axisViewportVertPos;
922 mAxisViewportHorizPos = axisViewportHorizPos;
923 onAxisViewportSizeUpdate();
924 mParentWindow->requestUpdate();
927 void Qgs3DAxis::onAxisViewportSizeUpdate(
int )
929 float widthRatio = ( float )mAxisViewportSize / mParentWindow->width();
930 float heightRatio = ( float )mAxisViewportSize / mParentWindow->height();
934 if ( mAxisViewportHorizPos == Qt::AnchorPoint::AnchorLeft )
936 else if ( mAxisViewportHorizPos == Qt::AnchorPoint::AnchorHorizontalCenter )
937 xRatio = 0.5 - widthRatio / 2.0;
939 xRatio = 1.0 - widthRatio;
941 if ( mAxisViewportVertPos == Qt::AnchorPoint::AnchorTop )
943 else if ( mAxisViewportVertPos == Qt::AnchorPoint::AnchorVerticalCenter )
944 yRatio = 0.5 - heightRatio / 2.0;
946 yRatio = 1.0 - heightRatio;
949 qDebug() <<
"Axis, update viewport" << xRatio << yRatio << widthRatio << heightRatio;
951 mAxisViewport->setNormalizedRect( QRectF( xRatio, yRatio, widthRatio, heightRatio ) );
953 mTwoDLabelCamera->lens()->setOrthographicProjection(
954 -mParentWindow->width() / 2.0f, mParentWindow->width() / 2.0f,
955 -mParentWindow->height() / 2.0f, mParentWindow->height() / 2.0f,
956 mTwoDLabelCamera->lens()->nearPlane(), mTwoDLabelCamera->lens()->farPlane() );
958 updateAxisLabelPosition();
961 void Qgs3DAxis::onCameraUpdate( )
963 Qt3DRender::QCamera *parentCamera = mCameraController->
camera();
965 if ( parentCamera->viewVector() != mPreviousVector
966 && !std::isnan( parentCamera->viewVector().x() )
967 && !std::isnan( parentCamera->viewVector().y() )
968 && !std::isnan( parentCamera->viewVector().z() ) )
970 mPreviousVector = parentCamera->viewVector();
971 QVector3D mainCameraShift = parentCamera->viewVector().normalized();
972 float zy_swap = mainCameraShift.y();
973 mainCameraShift.setY( mainCameraShift.z() );
974 mainCameraShift.setZ( -zy_swap );
975 mainCameraShift.setX( -mainCameraShift.x() );
977 if ( mAxisCamera->projectionType() == Qt3DRender::QCameraLens::ProjectionType::OrthographicProjection )
979 mAxisCamera->setPosition( mainCameraShift );
983 mAxisCamera->setPosition( mainCameraShift * mCylinderLength * 10.0 );
986 if ( mAxisRoot->isEnabled() )
988 updateAxisLabelPosition();
993 void Qgs3DAxis::updateAxisLabelPosition()
995 if ( mTextTransformX && mTextTransformY && mTextTransformZ )
998 mTwoDLabelCamera, mTwoDLabelViewport,
999 mParentWindow->size() ) );
1001 mTwoDLabelCamera, mTwoDLabelViewport,
1002 mParentWindow->size() ) );
1004 mTwoDLabelCamera, mTwoDLabelViewport,
1005 mParentWindow->size() ) );
1011 if ( mMode != axisMode )
1015 mParentWindow->requestUpdate();
1026 mPositionAttribute( new
Qt3DRender::QAttribute( this ) ),
1027 mVertexBuffer( new
Qt3DRender::QBuffer( this ) )
1029 mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
1030 mPositionAttribute->setBuffer( mVertexBuffer );
1031 mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
1032 mPositionAttribute->setVertexSize( 3 );
1033 mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
1035 mGeom =
new Qt3DRender::QGeometry(
this );
1036 mGeom->addAttribute( mPositionAttribute );
1038 setInstanceCount( 1 );
1039 setIndexOffset( 0 );
1040 setFirstInstance( 0 );
1041 setPrimitiveType( Qt3DRender::QGeometryRenderer::Lines );
1042 setGeometry( mGeom );
1049 QByteArray vertexBufferData;
1050 vertexBufferData.resize( vertices.size() * 3 *
sizeof(
float ) );
1051 float *rawVertexArray =
reinterpret_cast<float *
>( vertexBufferData.data() );
1053 for (
const QVector3D &v : std::as_const( vertices ) )
1055 rawVertexArray[idx++] = v.x();
1056 rawVertexArray[idx++] = v.y();
1057 rawVertexArray[idx++] = v.z();
1060 mVertexBuffer->setData( vertexBufferData );
1061 setVertexCount( vertices.count() );