Skip to content

Commit

Permalink
Added 3d map tool to change point cloud attribute values
Browse files Browse the repository at this point in the history
  • Loading branch information
uclaros committed Jan 16, 2025
1 parent 9f055dd commit ea2e1e5
Show file tree
Hide file tree
Showing 14 changed files with 621 additions and 5 deletions.
7 changes: 7 additions & 0 deletions python/3d/auto_generated/qgscameracontroller.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ Reacts to the shift of origin of the scene, updating camera pose and
any other member variables so that the origin stays at the same position
relative to other entities.

.. versionadded:: 3.42
%End

void setInputHandlersEnabled( bool enable );
%Docstring
Sets whether the camera controller responds to mouse and keyboard events

.. versionadded:: 3.42
%End

Expand Down
7 changes: 7 additions & 0 deletions python/PyQt6/3d/auto_generated/qgscameracontroller.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ Reacts to the shift of origin of the scene, updating camera pose and
any other member variables so that the origin stays at the same position
relative to other entities.

.. versionadded:: 3.42
%End

void setInputHandlersEnabled( bool enable );
%Docstring
Sets whether the camera controller responds to mouse and keyboard events

.. versionadded:: 3.42
%End

Expand Down
18 changes: 18 additions & 0 deletions src/3d/qgscameracontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ void QgsCameraController::moveCameraPositionBy( const QVector3D &posDiff )

void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
{
if ( !mInputHandlersEnabled )
return;

switch ( mCameraNavigationMode )
{
case Qgis::NavigationMode::TerrainBased:
Expand Down Expand Up @@ -573,6 +576,9 @@ void QgsCameraController::handleTerrainNavigationWheelZoom()

void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
{
if ( !mInputHandlersEnabled )
return;

switch ( mCameraNavigationMode )
{
case Qgis::NavigationMode::Walk:
Expand Down Expand Up @@ -605,6 +611,9 @@ void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )

void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
{
if ( !mInputHandlersEnabled )
return;

mKeyboardHandler->setFocus( true );

if ( mouse->button() == Qt3DInput::QMouseEvent::MiddleButton || ( ( mouse->modifiers() & Qt::ShiftModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) || ( ( mouse->modifiers() & Qt::ControlModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) )
Expand Down Expand Up @@ -635,12 +644,18 @@ void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
{
Q_UNUSED( mouse )
if ( !mInputHandlersEnabled )
return;


setMouseParameters( MouseOperation::None );
}

void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
{
if ( !mInputHandlersEnabled )
return;

if ( event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_QuoteLeft )
{
// switch navigation mode
Expand Down Expand Up @@ -933,6 +948,9 @@ void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent

void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
{
if ( !mInputHandlersEnabled )
return;

if ( event->isAutoRepeat() )
return;

Expand Down
7 changes: 7 additions & 0 deletions src/3d/qgscameracontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ class _3D_EXPORT QgsCameraController : public QObject
*/
void setOrigin( const QgsVector3D &origin );

/**
* Sets whether the camera controller responds to mouse and keyboard events
* \since QGIS 3.42
*/
void setInputHandlersEnabled( bool enable ) { mInputHandlersEnabled = enable; }

public slots:

/**
Expand Down Expand Up @@ -347,6 +353,7 @@ class _3D_EXPORT QgsCameraController : public QObject

Qt3DInput::QMouseHandler *mMouseHandler = nullptr;
Qt3DInput::QKeyboardHandler *mKeyboardHandler = nullptr;
bool mInputHandlersEnabled = true;
Qgis::NavigationMode mCameraNavigationMode = Qgis::NavigationMode::TerrainBased;
Qgis::VerticalAxisInversion mVerticalAxisInversion = Qgis::VerticalAxisInversion::WhenDragging;
double mCameraMovementSpeed = 5.0;
Expand Down
2 changes: 2 additions & 0 deletions src/3d/qgsrubberband3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class _3D_EXPORT QgsRubberBand3D
//! Sets whether the marker on the last vertex is displayed. We typically do not want it displayed while it is still tracked by the mouse.
void setHideLastMarker( bool hide ) { mHideLastMarker = hide; }

bool isEmpty() const { return mLineString.isEmpty(); }

private:
void updateGeometry();
void updateMarkerMaterial();
Expand Down
195 changes: 194 additions & 1 deletion src/app/3d/qgs3dmapcanvaswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "qgs3dmapsettings.h"
#include "qgs3dmaptoolidentify.h"
#include "qgs3dmaptoolmeasureline.h"
#include "qgs3dmaptoolpointcloudchangeattribute.h"
#include "qgs3dnavigationwidget.h"
#include "qgs3ddebugwidget.h"
#include "qgs3dutils.h"
Expand All @@ -57,6 +58,7 @@

#include "qgsdockablewidgethelper.h"
#include "qgsrubberband.h"
#include "qgspointcloudlayer.h"

#include <QWidget>
#include <QActionGroup>
Expand All @@ -75,6 +77,24 @@ Qgs3DMapCanvasWidget::Qgs3DMapCanvasWidget( const QString &name, bool isDocked )

toolBar->addAction( QgsApplication::getThemeIcon( QStringLiteral( "mActionZoomFullExtent.svg" ) ), tr( "Zoom Full" ), this, &Qgs3DMapCanvasWidget::resetView );

// Editing toolbar
mEditingToolBar = new QToolBar( this );
mEditingToolBar->setVisible( false );

QAction *actionPointCloudChangeAttributeTool = mEditingToolBar->addAction( QIcon( QgsApplication::iconPath( "mActionSelectPolygon.svg" ) ), tr( "Change Point Cloud Attribute" ), this, &Qgs3DMapCanvasWidget::changePointCloudAttribute );
actionPointCloudChangeAttributeTool->setCheckable( true );

mEditingToolBar->addWidget( new QLabel( tr( "Attribute:" ) ) );
mCboChangeAttribute = new QComboBox();
mEditingToolBar->addWidget( mCboChangeAttribute );
mSpinChangeAttributeValue = new QgsDoubleSpinBox();
mEditingToolBar->addWidget( new QLabel( tr( "Value:" ) ) );
mEditingToolBar->addWidget( mSpinChangeAttributeValue );
QAction *actionEditingToolbar = toolBar->addAction( QIcon( QgsApplication::iconPath( "mIconPointCloudLayer.svg" ) ), tr( "Show Editing Toolbar" ), this, [this] { mEditingToolBar->setVisible( !mEditingToolBar->isVisible() ); } );
actionEditingToolbar->setCheckable( true );
connect( mCboChangeAttribute, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) { onPointCloudChangeAttributeSettingsChanged(); } );
connect( mSpinChangeAttributeValue, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( double ) { onPointCloudChangeAttributeSettingsChanged(); } );

QAction *toggleOnScreenNavigation = toolBar->addAction(
QgsApplication::getThemeIcon( QStringLiteral( "mAction3DNavigation.svg" ) ),
tr( "Toggle On-Screen Navigation" )
Expand All @@ -99,8 +119,8 @@ Qgs3DMapCanvasWidget::Qgs3DMapCanvasWidget( const QString &name, bool isDocked )
actionGroup->addAction( actionCameraControl );
actionGroup->addAction( actionIdentify );
actionGroup->addAction( actionMeasurementTool );
actionGroup->addAction( actionPointCloudChangeAttributeTool );
actionGroup->setExclusive( true );
actionCameraControl->setChecked( true );

mActionAnim = toolBar->addAction( QIcon( QgsApplication::iconPath( "mTaskRunning.svg" ) ), tr( "Animations" ), this, &Qgs3DMapCanvasWidget::toggleAnimations );
mActionAnim->setCheckable( true );
Expand Down Expand Up @@ -237,6 +257,9 @@ Qgs3DMapCanvasWidget::Qgs3DMapCanvasWidget( const QString &name, bool isDocked )

mMapToolMeasureLine = new Qgs3DMapToolMeasureLine( mCanvas );

mMapToolPointCloudChangeAttribute = new Qgs3DMapToolPointCloudChangeAttribute( mCanvas );
onPointCloudChangeAttributeSettingsChanged();

mLabelPendingJobs = new QLabel( this );
mProgressPendingJobs = new QProgressBar( this );
mProgressPendingJobs->setRange( 0, 0 );
Expand Down Expand Up @@ -271,6 +294,7 @@ Qgs3DMapCanvasWidget::Qgs3DMapCanvasWidget( const QString &name, bool isDocked )
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 0 );
layout->addLayout( topLayout );
layout->addWidget( mEditingToolBar );
layout->addWidget( mMessageBar );

// mContainer takes ownership of Qgs3DMapCanvas
Expand Down Expand Up @@ -317,6 +341,8 @@ Qgs3DMapCanvasWidget::Qgs3DMapCanvasWidget( const QString &name, bool isDocked )
connect( dockAction, &QAction::toggled, this, [=]( const bool isSmallSize ) {
toolBar->setIconSize( QgisApp::instance()->iconSize( isSmallSize ) );
} );

updateLayerRelatedActions( QgisApp::instance()->activeLayer() );
}

Qgs3DMapCanvasWidget::~Qgs3DMapCanvasWidget()
Expand Down Expand Up @@ -377,12 +403,55 @@ void Qgs3DMapCanvasWidget::measureLine()
mCanvas->setMapTool( action->isChecked() ? mMapToolMeasureLine : nullptr );
}

void Qgs3DMapCanvasWidget::changePointCloudAttribute()
{
QAction *action = qobject_cast<QAction *>( sender() );
if ( !action )
return;

mCanvas->setMapTool( action->isChecked() ? mMapToolPointCloudChangeAttribute : nullptr );
}

void Qgs3DMapCanvasWidget::setCanvasName( const QString &name )
{
mCanvasName = name;
mDockableWidgetHelper->setWindowTitle( name );
}

void Qgs3DMapCanvasWidget::enableEditingTools( bool enable )
{
mEditingToolBar->setEnabled( enable );
}

void Qgs3DMapCanvasWidget::updateLayerRelatedActions( QgsMapLayer *layer )
{
if ( !layer || layer->type() != Qgis::LayerType::PointCloud )
{
enableEditingTools( false );

if ( mCanvas->mapTool() == mMapToolPointCloudChangeAttribute )
mCanvas->setMapTool( nullptr );

return;
}

QgsPointCloudLayer *pcLayer = qobject_cast<QgsPointCloudLayer *>( layer );
const QVector<QgsPointCloudAttribute> attributes = pcLayer->attributes().attributes();
const QString previousAttribute = mCboChangeAttribute->currentText();
whileBlocking( mCboChangeAttribute )->clear();
for ( const QgsPointCloudAttribute &attribute : attributes )
{
if ( attribute.name() == QLatin1String( "X" ) || attribute.name() == QLatin1String( "Y" ) || attribute.name() == QLatin1String( "Z" ) )
continue;

whileBlocking( mCboChangeAttribute )->addItem( attribute.name() );
}
if ( mCboChangeAttribute->findText( previousAttribute ) != -1 )
mCboChangeAttribute->setCurrentText( previousAttribute );

enableEditingTools( pcLayer->isEditable() );
}

void Qgs3DMapCanvasWidget::toggleNavigationWidget( bool visibility )
{
mNavigationWidget->setVisible( visibility );
Expand Down Expand Up @@ -734,6 +803,130 @@ void Qgs3DMapCanvasWidget::onGpuMemoryLimitReached()
mGpuMemoryLimitReachedReported = true;
}

void Qgs3DMapCanvasWidget::onPointCloudChangeAttributeSettingsChanged()
{
const QString attributeName = mCboChangeAttribute->currentText();

if ( attributeName == QLatin1String( "Intensity" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "ReturnNumber" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 15 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "NumberOfReturns" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 15 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Synthetic" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "KeyPoint" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Withheld" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Overlap" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "ScannerChannel" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 3 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "ScanDirectionFlag" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "EdgeOfFlightLine" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 1 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Classification" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 255 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "UserData" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 255 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "ScanAngleRank" ) )
{
mSpinChangeAttributeValue->setMinimum( -30'000 );
mSpinChangeAttributeValue->setMaximum( 30'000 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "PointSourceId" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "GpsTime" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( std::numeric_limits<double>::max() );
mSpinChangeAttributeValue->setDecimals( 42 );
}
else if ( attributeName == QLatin1String( "Red" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Green" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Blue" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}
else if ( attributeName == QLatin1String( "Infrared" ) )
{
mSpinChangeAttributeValue->setMinimum( 0 );
mSpinChangeAttributeValue->setMaximum( 65535 );
mSpinChangeAttributeValue->setDecimals( 0 );
}

mMapToolPointCloudChangeAttribute->setAttribute( attributeName );
// TODO: validate values for attribute
mMapToolPointCloudChangeAttribute->setNewValue( mSpinChangeAttributeValue->value() );
}

void Qgs3DMapCanvasWidget::setSceneExtentOn2DCanvas()
{
if ( !qobject_cast<QgsMapToolExtent *>( mMainCanvas->mapTool() ) )
Expand Down
Loading

0 comments on commit ea2e1e5

Please sign in to comment.