QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgspointcloudquerybuilder.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudquerybuilder.cpp - Query builder for point cloud layers
3 -----------------------------
4 begin : March 2022
5 copyright : (C) 2022 by Stefanos Natsis
6 email : uclaros at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
16
17#include "qgsgui.h"
18#include "qgshelp.h"
19#include "qgspointcloudexpression.h"
20#include "qgspointcloudlayer.h"
21#include "qgsquerybuilder.h"
22#include "qgssettings.h"
23
24#include <QDomDocument>
25#include <QDomElement>
26#include <QFileDialog>
27#include <QListView>
28#include <QMessageBox>
29#include <QPushButton>
30#include <QTextStream>
31
32#include "moc_qgspointcloudquerybuilder.cpp"
33
35 : QgsSubsetStringEditorInterface( parent, fl )
36 , mLayer( layer )
37{
38 setupUi( this );
40
41 setupGuiViews();
42 populateAttributes();
43
44 connect( lstAttributes->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsPointCloudQueryBuilder::lstAttributes_currentChanged );
45 connect( lstAttributes, &QListView::doubleClicked, this, &QgsPointCloudQueryBuilder::lstAttributes_doubleClicked );
46 connect( lstValues, &QListView::doubleClicked, this, &QgsPointCloudQueryBuilder::lstValues_doubleClicked );
47 connect( btnEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnEqual_clicked );
48 connect( btnLessThan, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnLessThan_clicked );
49 connect( btnGreaterThan, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnGreaterThan_clicked );
50 connect( btnIn, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnIn_clicked );
51 connect( btnNotIn, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnNotIn_clicked );
52 connect( btnLessEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnLessEqual_clicked );
53 connect( btnGreaterEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnGreaterEqual_clicked );
54 connect( btnNotEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnNotEqual_clicked );
55 connect( btnAnd, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnAnd_clicked );
56 connect( btnOr, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnOr_clicked );
57
58 QPushButton *pbn = new QPushButton( tr( "&Test" ) );
59 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
60 connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::test );
61
62 pbn = new QPushButton( tr( "&Clear" ) );
63 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
64 connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::clear );
65
66 pbn = new QPushButton( tr( "&Save…" ) );
67 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
68 pbn->setToolTip( tr( "Save query to QQF file" ) );
69 connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::saveQuery );
70
71 pbn = new QPushButton( tr( "&Load…" ) );
72 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
73 pbn->setToolTip( tr( "Load query from QQF file" ) );
74 connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::loadQuery );
75
76 lblDataUri->setText( tr( "Set provider filter on %1" ).arg( layer->name() ) );
77}
78
79void QgsPointCloudQueryBuilder::showEvent( QShowEvent *event )
80{
81 mTxtSql->setFocus();
82 QDialog::showEvent( event );
83}
84
85void QgsPointCloudQueryBuilder::setupGuiViews()
86{
87 //Initialize the models
88 mModelAttributes = new QStandardItemModel();
89 mModelValues = new QStandardItemModel();
90
91 // Modes
92 lstAttributes->setViewMode( QListView::ListMode );
93 lstValues->setViewMode( QListView::ListMode );
94 lstAttributes->setSelectionBehavior( QAbstractItemView::SelectRows );
95 lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
96 lstAttributes->setEditTriggers( QAbstractItemView::NoEditTriggers );
97 lstValues->setEditTriggers( QAbstractItemView::NoEditTriggers );
98 // Performance tip since Qt 4.1
99 lstAttributes->setUniformItemSizes( true );
100 lstValues->setUniformItemSizes( true );
101 // Colored rows
102 lstAttributes->setAlternatingRowColors( true );
103 lstValues->setAlternatingRowColors( true );
104
105 lstAttributes->setModel( mModelAttributes );
106 lstValues->setModel( mModelValues );
107}
108
109void QgsPointCloudQueryBuilder::populateAttributes()
110{
111 const QgsFields &fields = mLayer->dataProvider()->attributes().toFields();
112 mTxtSql->setFields( fields );
113 for ( int idx = 0; idx < fields.count(); ++idx )
114 {
115 QStandardItem *myItem = new QStandardItem( fields.at( idx ).displayNameWithAlias() );
116 mModelAttributes->insertRow( mModelAttributes->rowCount(), myItem );
117 }
118}
119
120void QgsPointCloudQueryBuilder::lstAttributes_currentChanged( const QModelIndex &current, const QModelIndex &previous )
121{
122 Q_UNUSED( previous )
123
124 mModelValues->clear();
125 const QString attribute = current.data().toString();
126 if ( attribute.compare( QLatin1String( "Classification" ), Qt::CaseInsensitive ) == 0 )
127 {
128 const QMap<int, QString> codes = QgsPointCloudDataProvider::translatedLasClassificationCodes();
129 for ( int i = 0; i <= 18; ++i )
130 {
131 QStandardItem *item = new QStandardItem( QString( "%1: %2" ).arg( i ).arg( codes.value( i ) ) );
132 item->setData( i, Qt::UserRole );
133 mModelValues->insertRow( mModelValues->rowCount(), item );
134 }
135 }
136 else
137 {
138 const QgsPointCloudStatistics stats = mLayer->statistics();
139 double value = stats.minimum( attribute );
140 QString valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
141 QStandardItem *item = new QStandardItem( tr( "Minimum: %1" ).arg( valueString ) );
142 item->setData( value, Qt::UserRole );
143 mModelValues->insertRow( mModelValues->rowCount(), item );
144
145 value = stats.maximum( attribute );
146 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
147 item = new QStandardItem( tr( "Maximum: %1" ).arg( valueString ) );
148 item->setData( value, Qt::UserRole );
149 mModelValues->insertRow( mModelValues->rowCount(), item );
150
151 value = stats.mean( attribute );
152 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
153 item = new QStandardItem( tr( "Mean: %1" ).arg( valueString ) );
154 item->setData( value, Qt::UserRole );
155 mModelValues->insertRow( mModelValues->rowCount(), item );
156
157 value = stats.stDev( attribute );
158 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
159 item = new QStandardItem( tr( "StdDev: %1" ).arg( valueString ) );
160 item->setData( value, Qt::UserRole );
161 mModelValues->insertRow( mModelValues->rowCount(), item );
162 }
163}
164
165void QgsPointCloudQueryBuilder::lstAttributes_doubleClicked( const QModelIndex &index )
166{
167 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelAttributes->data( index ).toString() ) );
168 mTxtSql->setFocus();
169}
170
171void QgsPointCloudQueryBuilder::lstValues_doubleClicked( const QModelIndex &index )
172{
173 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelValues->data( index, Qt::UserRole ).toString() ) );
174 mTxtSql->setFocus();
175}
176
177void QgsPointCloudQueryBuilder::btnEqual_clicked()
178{
179 mTxtSql->insertText( QStringLiteral( "= " ) );
180 mTxtSql->setFocus();
181}
182
183void QgsPointCloudQueryBuilder::btnLessThan_clicked()
184{
185 mTxtSql->insertText( QStringLiteral( "< " ) );
186 mTxtSql->setFocus();
187}
188
189void QgsPointCloudQueryBuilder::btnGreaterThan_clicked()
190{
191 mTxtSql->insertText( QStringLiteral( "> " ) );
192 mTxtSql->setFocus();
193}
194
195void QgsPointCloudQueryBuilder::btnIn_clicked()
196{
197 mTxtSql->insertText( QStringLiteral( "IN () " ) );
198 int i, j;
199 mTxtSql->getCursorPosition( &i, &j );
200 mTxtSql->setCursorPosition( i, j - 2 );
201 mTxtSql->setFocus();
202}
203
204void QgsPointCloudQueryBuilder::btnNotIn_clicked()
205{
206 mTxtSql->insertText( QStringLiteral( "NOT IN () " ) );
207 int i, j;
208 mTxtSql->getCursorPosition( &i, &j );
209 mTxtSql->setCursorPosition( i, j - 2 );
210 mTxtSql->setFocus();
211}
212
213void QgsPointCloudQueryBuilder::btnLessEqual_clicked()
214{
215 mTxtSql->insertText( QStringLiteral( "<= " ) );
216 mTxtSql->setFocus();
217}
218
219void QgsPointCloudQueryBuilder::btnGreaterEqual_clicked()
220{
221 mTxtSql->insertText( QStringLiteral( ">= " ) );
222 mTxtSql->setFocus();
223}
224
225void QgsPointCloudQueryBuilder::btnNotEqual_clicked()
226{
227 mTxtSql->insertText( QStringLiteral( "!= " ) );
228 mTxtSql->setFocus();
229}
230
231void QgsPointCloudQueryBuilder::btnAnd_clicked()
232{
233 mTxtSql->insertText( QStringLiteral( "AND " ) );
234 mTxtSql->setFocus();
235}
236
237void QgsPointCloudQueryBuilder::btnOr_clicked()
238{
239 mTxtSql->insertText( QStringLiteral( "OR " ) );
240 mTxtSql->setFocus();
241}
242
244{
245 if ( !test( true ) )
246 return;
247
248 QDialog::accept();
249}
250
252{
253 mTxtSql->setText( mOrigSubsetString );
254
255 QDialog::reject();
256}
257
258bool QgsPointCloudQueryBuilder::test( bool skipConfirmation )
259{
260 QgsPointCloudExpression expression( mTxtSql->text() );
261 if ( !expression.isValid() && !mTxtSql->text().isEmpty() )
262 {
263 QMessageBox::warning( this, tr( "Query Result" ), tr( "An error occurred while parsing the expression:\n%1" ).arg( expression.parserErrorString() ) );
264 return false;
265 }
266 else
267 {
268 const QSet<QString> attributes = expression.referencedAttributes();
269 int offset;
270 for ( const auto &attribute : attributes )
271 {
272 if ( mLayer->dataProvider() && !mLayer->dataProvider()->attributes().find( attribute, offset ) )
273 {
274 QMessageBox::warning( this, tr( "Query Result" ), tr( "\"%1\" not recognized as an available attribute." ).arg( attribute ) );
275 return false;
276 }
277 }
278
279 if ( !skipConfirmation )
280 QMessageBox::information( this, tr( "Query Result" ), tr( "The expression was successfully parsed." ) );
281 }
282 return true;
283}
284
285void QgsPointCloudQueryBuilder::clear()
286{
287 mTxtSql->clear();
288}
289
290void QgsPointCloudQueryBuilder::saveQuery()
291{
292 const bool ok = QgsQueryBuilder::saveQueryToFile( mTxtSql->text() );
293 Q_UNUSED( ok )
294}
295
296void QgsPointCloudQueryBuilder::loadQuery()
297{
298 QString subset;
300 {
301 mTxtSql->clear();
302 mTxtSql->insertText( subset );
303 }
304}
QString displayNameWithAlias() const
Returns the name to use when displaying this field and adds the alias in parenthesis if it is defined...
Definition qgsfield.cpp:105
int count
Definition qgsfields.h:50
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:221
QString name
Definition qgsmaplayer.h:84
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
Represents a map layer supporting display of point clouds.
QgsPointCloudQueryBuilder(QgsPointCloudLayer *layer, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
This constructor is used when the query builder is called from the layer properties dialog.
void showEvent(QShowEvent *event) override
double maximum(const QString &attribute) const
Returns the maximum value for the attribute attribute If no matching statistic is available then NaN ...
double stDev(const QString &attribute) const
Returns the standard deviation value for the attribute attribute If no matching statistic is availabl...
double mean(const QString &attribute) const
Returns the mean value for the attribute attribute If no matching statistic is available then NaN wil...
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...
static bool loadQueryFromFile(QString &subset)
Load query from the XML file.
static bool saveQueryToFile(const QString &subset)
Save query to the XML file.
QgsSubsetStringEditorInterface(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor.