QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 #include "qgssettings.h"
17 #include "qgspointcloudlayer.h"
18 #include "qgspointcloudexpression.h"
19 #include "qgshelp.h"
20 #include "qgsgui.h"
21 #include "qgsquerybuilder.h"
22 
23 #include <QDomDocument>
24 #include <QDomElement>
25 #include <QFileDialog>
26 #include <QListView>
27 #include <QMessageBox>
28 #include <QPushButton>
29 #include <QTextStream>
30 
31 
33  QWidget *parent, Qt::WindowFlags fl )
34  : QgsSubsetStringEditorInterface( parent, fl )
35  , mLayer( layer )
36 {
37  setupUi( this );
39 
40  setupGuiViews();
41  populateAttributes();
42 
43  connect( lstAttributes->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsPointCloudQueryBuilder::lstAttributes_currentChanged );
44  connect( lstAttributes, &QListView::doubleClicked, this, &QgsPointCloudQueryBuilder::lstAttributes_doubleClicked );
45  connect( lstValues, &QListView::doubleClicked, this, &QgsPointCloudQueryBuilder::lstValues_doubleClicked );
46  connect( btnEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnEqual_clicked );
47  connect( btnLessThan, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnLessThan_clicked );
48  connect( btnGreaterThan, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnGreaterThan_clicked );
49  connect( btnIn, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnIn_clicked );
50  connect( btnNotIn, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnNotIn_clicked );
51  connect( btnLessEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnLessEqual_clicked );
52  connect( btnGreaterEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnGreaterEqual_clicked );
53  connect( btnNotEqual, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnNotEqual_clicked );
54  connect( btnAnd, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnAnd_clicked );
55  connect( btnOr, &QPushButton::clicked, this, &QgsPointCloudQueryBuilder::btnOr_clicked );
56 
57  QPushButton *pbn = new QPushButton( tr( "&Test" ) );
58  buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
59  connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::test );
60 
61  pbn = new QPushButton( tr( "&Clear" ) );
62  buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
63  connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::clear );
64 
65  pbn = new QPushButton( tr( "&Save…" ) );
66  buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
67  pbn->setToolTip( tr( "Save query to QQF file" ) );
68  connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::saveQuery );
69 
70  pbn = new QPushButton( tr( "&Load…" ) );
71  buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
72  pbn->setToolTip( tr( "Load query from QQF file" ) );
73  connect( pbn, &QAbstractButton::clicked, this, &QgsPointCloudQueryBuilder::loadQuery );
74 
75  mOrigSubsetString = layer->subsetString();
76 
77  lblDataUri->setText( tr( "Set provider filter on %1" ).arg( layer->name() ) );
78  mTxtSql->setText( mOrigSubsetString );
79 }
80 
81 void QgsPointCloudQueryBuilder::showEvent( QShowEvent *event )
82 {
83  mTxtSql->setFocus();
84  QDialog::showEvent( event );
85 }
86 
87 void QgsPointCloudQueryBuilder::setupGuiViews()
88 {
89  //Initialize the models
90  mModelAttributes = new QStandardItemModel();
91  mModelValues = new QStandardItemModel();
92 
93  // Modes
94  lstAttributes->setViewMode( QListView::ListMode );
95  lstValues->setViewMode( QListView::ListMode );
96  lstAttributes->setSelectionBehavior( QAbstractItemView::SelectRows );
97  lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
98  lstAttributes->setEditTriggers( QAbstractItemView::NoEditTriggers );
99  lstValues->setEditTriggers( QAbstractItemView::NoEditTriggers );
100  // Performance tip since Qt 4.1
101  lstAttributes->setUniformItemSizes( true );
102  lstValues->setUniformItemSizes( true );
103  // Colored rows
104  lstAttributes->setAlternatingRowColors( true );
105  lstValues->setAlternatingRowColors( true );
106 
107  lstAttributes->setModel( mModelAttributes );
108  lstValues->setModel( mModelValues );
109 }
110 
111 void QgsPointCloudQueryBuilder::populateAttributes()
112 {
113  const QgsFields &fields = mLayer->dataProvider()->index()->attributes().toFields();
114  mTxtSql->setFields( fields );
115  for ( int idx = 0; idx < fields.count(); ++idx )
116  {
117  QStandardItem *myItem = new QStandardItem( fields.at( idx ).displayNameWithAlias() );
118  mModelAttributes->insertRow( mModelAttributes->rowCount(), myItem );
119  }
120 }
121 
122 void QgsPointCloudQueryBuilder::lstAttributes_currentChanged( const QModelIndex &current, const QModelIndex &previous )
123 {
124  Q_UNUSED( previous )
125 
126  mModelValues->clear();
127  const QString attribute = current.data().toString();
128  if ( attribute.compare( QLatin1String( "Classification" ), Qt::CaseInsensitive ) == 0 )
129  {
130  const QMap<int, QString> codes = QgsPointCloudDataProvider::translatedLasClassificationCodes();
131  for ( int i = 0; i <= 18; ++i )
132  {
133  QStandardItem *item = new QStandardItem( QString( "%1: %2" ).arg( i ).arg( codes.value( i ) ) );
134  item->setData( i, Qt::UserRole );
135  mModelValues->insertRow( mModelValues->rowCount(), item );
136  }
137  }
138  else
139  {
140  const QgsPointCloudStatistics stats = mLayer->statistics();
141  double value = stats.minimum( attribute );
142  QString valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
143  QStandardItem *item = new QStandardItem( tr( "Minimum: %1" ).arg( valueString ) );
144  item->setData( value, Qt::UserRole );
145  mModelValues->insertRow( mModelValues->rowCount(), item );
146 
147  value = stats.maximum( attribute );
148  valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
149  item = new QStandardItem( tr( "Maximum: %1" ).arg( valueString ) );
150  item->setData( value, Qt::UserRole );
151  mModelValues->insertRow( mModelValues->rowCount(), item );
152 
153  value = stats.mean( attribute );
154  valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
155  item = new QStandardItem( tr( "Mean: %1" ).arg( valueString ) );
156  item->setData( value, Qt::UserRole );
157  mModelValues->insertRow( mModelValues->rowCount(), item );
158 
159  value = stats.stDev( attribute );
160  valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
161  item = new QStandardItem( tr( "StdDev: %1" ).arg( valueString ) );
162  item->setData( value, Qt::UserRole );
163  mModelValues->insertRow( mModelValues->rowCount(), item );
164  }
165 }
166 
167 void QgsPointCloudQueryBuilder::lstAttributes_doubleClicked( const QModelIndex &index )
168 {
169  mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelAttributes->data( index ).toString() ) );
170  mTxtSql->setFocus();
171 }
172 
173 void QgsPointCloudQueryBuilder::lstValues_doubleClicked( const QModelIndex &index )
174 {
175  mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelValues->data( index, Qt::UserRole ).toString() ) );
176  mTxtSql->setFocus();
177 }
178 
179 void QgsPointCloudQueryBuilder::btnEqual_clicked()
180 {
181  mTxtSql->insertText( QStringLiteral( "= " ) );
182  mTxtSql->setFocus();
183 }
184 
185 void QgsPointCloudQueryBuilder::btnLessThan_clicked()
186 {
187  mTxtSql->insertText( QStringLiteral( "< " ) );
188  mTxtSql->setFocus();
189 }
190 
191 void QgsPointCloudQueryBuilder::btnGreaterThan_clicked()
192 {
193  mTxtSql->insertText( QStringLiteral( "> " ) );
194  mTxtSql->setFocus();
195 }
196 
197 void QgsPointCloudQueryBuilder::btnIn_clicked()
198 {
199  mTxtSql->insertText( QStringLiteral( "IN () " ) );
200  int i, j;
201  mTxtSql->getCursorPosition( &i, &j );
202  mTxtSql->setCursorPosition( i, j - 2 );
203  mTxtSql->setFocus();
204 }
205 
206 void QgsPointCloudQueryBuilder::btnNotIn_clicked()
207 {
208  mTxtSql->insertText( QStringLiteral( "NOT IN () " ) );
209  int i, j;
210  mTxtSql->getCursorPosition( &i, &j );
211  mTxtSql->setCursorPosition( i, j - 2 );
212  mTxtSql->setFocus();
213 }
214 
215 void QgsPointCloudQueryBuilder::btnLessEqual_clicked()
216 {
217  mTxtSql->insertText( QStringLiteral( "<= " ) );
218  mTxtSql->setFocus();
219 }
220 
221 void QgsPointCloudQueryBuilder::btnGreaterEqual_clicked()
222 {
223  mTxtSql->insertText( QStringLiteral( ">= " ) );
224  mTxtSql->setFocus();
225 }
226 
227 void QgsPointCloudQueryBuilder::btnNotEqual_clicked()
228 {
229  mTxtSql->insertText( QStringLiteral( "!= " ) );
230  mTxtSql->setFocus();
231 }
232 
233 void QgsPointCloudQueryBuilder::btnAnd_clicked()
234 {
235  mTxtSql->insertText( QStringLiteral( "AND " ) );
236  mTxtSql->setFocus();
237 }
238 
239 void QgsPointCloudQueryBuilder::btnOr_clicked()
240 {
241  mTxtSql->insertText( QStringLiteral( "OR " ) );
242  mTxtSql->setFocus();
243 }
244 
246 {
247  if ( mTxtSql->text() != mOrigSubsetString )
248  {
249  if ( !mLayer->setSubsetString( mTxtSql->text() ) )
250  {
251  QMessageBox::warning( this, tr( "Query Result" ), tr( "Error in query. The subset string could not be set." ) );
252  return;
253  }
254  }
255 
256  QDialog::accept();
257 }
258 
260 {
261  if ( mLayer->subsetString() != mOrigSubsetString )
262  mLayer->setSubsetString( mOrigSubsetString );
263 
264  QDialog::reject();
265 }
266 
267 void QgsPointCloudQueryBuilder::test()
268 {
269  QgsPointCloudExpression expression( mTxtSql->text() );
270  if ( !expression.isValid() && !mTxtSql->text().isEmpty() )
271  {
272  QMessageBox::warning( this,
273  tr( "Query Result" ),
274  tr( "An error occurred while parsing the expression:\n%1" ).arg( expression.parserErrorString() ) );
275  }
276  else
277  {
278  const QSet<QString> attributes = expression.referencedAttributes();
279  int offset;
280  for ( const auto &attribute : attributes )
281  {
282  if ( mLayer->dataProvider() &&
283  !mLayer->dataProvider()->attributes().find( attribute, offset ) )
284  {
285  QMessageBox::warning( this,
286  tr( "Query Result" ),
287  tr( "\"%1\" not recognized as an available attribute." ).arg( attribute ) );
288  return;
289  }
290  }
291  mLayer->setSubsetString( mTxtSql->text() );
292  QMessageBox::information( this,
293  tr( "Query Result" ),
294  tr( "The expression was successfully parsed." ) );
295  }
296 }
297 
298 void QgsPointCloudQueryBuilder::clear()
299 {
300  mTxtSql->clear();
301  mLayer->setSubsetString( QString() );
302 }
303 
304 void QgsPointCloudQueryBuilder::saveQuery()
305 {
306  const bool ok = QgsQueryBuilder::saveQueryToFile( mTxtSql->text() );
307  Q_UNUSED( ok )
308 }
309 
310 void QgsPointCloudQueryBuilder::loadQuery()
311 {
312  QString subset;
313  if ( QgsQueryBuilder::loadQueryFromFile( subset ) )
314  {
315  mTxtSql->clear();
316  mTxtSql->insertText( subset );
317  }
318 }
QgsPointCloudStatistics::stDev
double stDev(const QString &attribute) const
Returns the standard deviation value for the attribute attribute If no matching statistic is availabl...
Definition: qgspointcloudstatistics.cpp:124
QgsSubsetStringEditorInterface
Interface for a dialog that can edit subset strings.
Definition: qgssubsetstringeditorinterface.h:33
QgsPointCloudAttributeCollection::find
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
Definition: qgspointcloudattribute.cpp:168
QgsPointCloudLayer::statistics
const QgsPointCloudStatistics statistics() const
Returns the object containing statistics.
Definition: qgspointcloudlayer.h:239
QgsPointCloudQueryBuilder::accept
void accept() override
Definition: qgspointcloudquerybuilder.cpp:245
QgsPointCloudLayer
Represents a map layer supporting display of point clouds.
Definition: qgspointcloudlayer.h:45
qgsgui.h
QgsField::displayNameWithAlias
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:97
QgsFields::count
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsPointCloudStatistics
Class used to store statistics of a point cloud dataset.
Definition: qgspointcloudstatistics.h:61
QgsPointCloudIndex::attributes
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
Definition: qgspointcloudindex.cpp:192
QgsPointCloudQueryBuilder::showEvent
void showEvent(QShowEvent *event) override
Definition: qgspointcloudquerybuilder.cpp:81
QgsPointCloudStatistics::maximum
double maximum(const QString &attribute) const
Returns the maximum value for the attribute attribute If no matching statistic is available then NaN ...
Definition: qgspointcloudstatistics.cpp:110
QgsPointCloudDataProvider::attributes
virtual QgsPointCloudAttributeCollection attributes() const =0
Returns the attributes available from this data provider.
qgsquerybuilder.h
QgsGui::enableAutoGeometryRestore
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:180
QgsPointCloudLayer::dataProvider
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Definition: qgspointcloudlayer.cpp:114
qgspointcloudlayer.h
QgsPointCloudQueryBuilder::QgsPointCloudQueryBuilder
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.
Definition: qgspointcloudquerybuilder.cpp:32
QgsPointCloudStatistics::mean
double mean(const QString &attribute) const
Returns the mean value for the attribute attribute If no matching statistic is available then NaN wil...
Definition: qgspointcloudstatistics.cpp:117
QgsQueryBuilder::loadQueryFromFile
static bool loadQueryFromFile(QString &subset)
Load query from the XML file.
Definition: qgsquerybuilder.cpp:520
QgsPointCloudStatistics::minimum
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...
Definition: qgspointcloudstatistics.cpp:103
QgsPointCloudLayer::setSubsetString
bool setSubsetString(const QString &subset)
Sets the string used to define a subset of the layer.
Definition: qgspointcloudlayer.cpp:729
QgsPointCloudQueryBuilder::reject
void reject() override
Definition: qgspointcloudquerybuilder.cpp:259
qgssettings.h
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:76
qgspointcloudquerybuilder.h
QgsPointCloudAttributeCollection::toFields
QgsFields toFields() const
Converts the attribute collection to an equivalent QgsFields collection.
Definition: qgspointcloudattribute.cpp:193
QgsPointCloudLayer::subsetString
QString subsetString() const
Returns the string used to define a subset of the layer.
Definition: qgspointcloudlayer.cpp:749
QgsFields::at
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
QgsPointCloudDataProvider::translatedLasClassificationCodes
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
Definition: qgspointclouddataprovider.cpp:105
qgshelp.h
QgsQueryBuilder::saveQueryToFile
static bool saveQueryToFile(const QString &subset)
Save query to the XML file.
Definition: qgsquerybuilder.cpp:473
QgsPointCloudDataProvider::index
virtual QgsPointCloudIndex * index() const
Returns the point cloud index associated with the provider.
Definition: qgspointclouddataprovider.h:164