SkaterDialog.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/sa/qt/SkaterDialog.cpp
22 
23  \brief A dialog for Spatial 'K'luster Analysis by Tree Edge Removal.
24 */
25 
26 // TerraLib
27 #include "../../core/logger/Logger.h"
28 #include "../../common/progress/ProgressManager.h"
29 #include "../../core/translator/Translator.h"
30 #include "../../common/STLUtils.h"
31 #include "../../dataaccess/datasource/DataSource.h"
32 #include "../../dataaccess/utils/Utils.h"
33 #include "../../geometry/GeometryProperty.h"
34 #include "../../maptools/DataSetLayer.h"
35 #include "../../qt/widgets/datasource/selector/DataSourceSelectorDialog.h"
36 #include "../../qt/widgets/progress/ProgressViewerDialog.h"
37 #include "../core/GPMBuilder.h"
38 #include "../core/GPMConstructorAdjacencyStrategy.h"
39 #include "../core/GPMWeightsNoWeightsStrategy.h"
40 #include "../core/SkaterOperation.h"
41 #include "../core/SkaterParams.h"
42 #include "../core/SpatialWeightsExchanger.h"
43 #include "../core/Utils.h"
44 #include "../Exception.h"
45 #include "SkaterDialog.h"
46 #include "Utils.h"
47 #include "ui_SkaterDialogForm.h"
48 
49 // Qt
50 #include <QFileDialog>
51 #include <QFileInfo>
52 #include <QGridLayout>
53 #include <QMessageBox>
54 #include <QValidator>
55 
56 // STL
57 #include <memory>
58 
59 // Boost
60 #include <boost/filesystem.hpp>
61 
63 
64 te::sa::SkaterDialog::SkaterDialog(QWidget* parent, Qt::WindowFlags f)
65  : QDialog(parent, f),
66  m_ui(new Ui::SkaterDialogForm)
67 {
68 // add controls
69  m_ui->setupUi(this);
70 
71 // add double list widget
72  m_doubleListWidget = new te::qt::widgets::DoubleListWidget(m_ui->m_widget);
73  m_doubleListWidget->setLeftLabel("Layer Attributes");
74  m_doubleListWidget->setRightLabel("Selected Attributes");
75  QGridLayout* layout = new QGridLayout(m_ui->m_widget);
76  layout->addWidget(m_doubleListWidget);
77  layout->setContentsMargins(0, 0, 0, 0);
78 
79 // add icons
80  m_ui->m_imgLabel->setPixmap(QIcon::fromTheme("sa-skater-hint").pixmap(112,48));
81  m_ui->m_targetDatasourceToolButton->setIcon(QIcon::fromTheme("datasource"));
82 
83 // connectors
84  connect(m_ui->m_inputLayerComboBox, SIGNAL(activated(int)), this, SLOT(onInputLayerComboBoxActivated(int)));
85  connect(m_ui->m_okPushButton, SIGNAL(clicked()), this, SLOT(onOkPushButtonClicked()));
86  connect(m_ui->m_targetDatasourceToolButton, SIGNAL(pressed()), this, SLOT(onTargetDatasourceToolButtonPressed()));
87  connect(m_ui->m_targetFileToolButton, SIGNAL(pressed()), this, SLOT(onTargetFileToolButtonPressed()));
88  connect(m_ui->m_gpmToolButton, SIGNAL(clicked()), this, SLOT(onGPMToolButtonClicked()));
89 
90 // help info
91  m_ui->m_helpPushButton->setNameSpace("dpi.inpe.br.plugins");
92  m_ui->m_helpPushButton->setPageReference("plugins/sa/sa_skater.html");
93 }
94 
96 
97 void te::sa::SkaterDialog::setLayers(std::list<te::map::AbstractLayerPtr> layers)
98 {
99  std::list<te::map::AbstractLayerPtr>::iterator it = layers.begin();
100 
101  while(it != layers.end())
102  {
104 
105  if(l->isValid())
106  {
107  std::unique_ptr<te::da::DataSetType> dsType = l->getSchema();
108  te::map::DataSetLayer* dsLayer = dynamic_cast<te::map::DataSetLayer*>(l.get());
109 
110  if(dsLayer && dsType->hasGeom())
111  m_ui->m_inputLayerComboBox->addItem(it->get()->getTitle().c_str(), QVariant::fromValue(l));
112  }
113 
114  ++it;
115  }
116 
117 // fill attributes combo
118  if(m_ui->m_inputLayerComboBox->count() > 0)
120 }
121 
123 {
124  return m_outputLayer;
125 }
126 
128 {
129  QVariant varLayer = m_ui->m_inputLayerComboBox->itemData(index, Qt::UserRole);
130 
132 
133  std::unique_ptr<te::da::DataSetType> dsType = l->getSchema();
134 
135  std::vector<te::dt::Property*> propVec = dsType->getProperties();
136 
137  m_ui->m_popComboBox->clear();
138  m_ui->m_attrLinkComboBox->clear();
139 
142 
143  std::vector<std::string> vec;
144 
145  for(std::size_t t = 0; t < propVec.size(); ++t)
146  {
147  int dataType = propVec[t]->getType();
148 
149  if (dataType == te::dt::INT16_TYPE || dataType == te::dt::UINT16_TYPE ||
150  dataType == te::dt::INT32_TYPE || dataType == te::dt::UINT32_TYPE ||
151  dataType == te::dt::INT64_TYPE || dataType == te::dt::UINT64_TYPE ||
152  dataType == te::dt::FLOAT_TYPE || dataType == te::dt::DOUBLE_TYPE)
153  {
154  m_ui->m_popComboBox->addItem(propVec[t]->getName().c_str(), dataType);
155 
156  vec.push_back(propVec[t]->getName());
157  }
158 
159  m_ui->m_attrLinkComboBox->addItem(propVec[t]->getName().c_str(), dataType);
160  }
161 
162  std::sort(vec.begin(), vec.end());
163 
165 }
166 
168 {
169  // check input parameters
170  if(m_ui->m_repositoryLineEdit->text().isEmpty())
171  {
172  QMessageBox::information(this, tr("Warning"), tr("Define a repository for the result."));
173  return;
174  }
175 
176  if(m_ui->m_newLayerNameLineEdit->text().isEmpty())
177  {
178  QMessageBox::information(this, tr("Warning"), tr("Define a name for the resulting layer."));
179  return;
180  }
181 
182  if(!m_ui->m_clustersCheckBox->isChecked() && !m_ui->m_popCheckBox->isChecked())
183  {
184  QMessageBox::information(this, tr("Warning"), tr("Select the aggregation type."));
185  return;
186  }
187 
188  if(m_ui->m_clustersCheckBox->isChecked())
189  {
190  if(m_ui->m_nClustersLineEdit->text().isEmpty())
191  {
192  QMessageBox::information(this, tr("Warning"), tr("Number of clusters not defined."));
193  return;
194  }
195  }
196 
197  if(m_ui->m_popCheckBox->isChecked())
198  {
199  if(m_ui->m_minPopLineEdit->text().isEmpty())
200  {
201  QMessageBox::information(this, tr("Warning"), tr("Minimum population not defined."));
202  return;
203  }
204  }
205 
206  std::vector<std::string> attrs = m_doubleListWidget->getOutputValues();
207 
208  if(attrs.empty())
209  {
210  QMessageBox::information(this, tr("Warning"), tr("Select the attributes."));
211  return;
212  }
213 
214  //get GPM
215  std::unique_ptr<te::sa::GeneralizedProximityMatrix> gpm;
216 
217  try
218  {
219  gpm = loadGPM();
220  }
221  catch(...)
222  {
223  QMessageBox::warning(this, tr("Warning"), tr("Internal error. GPM not loaded."));
224  return;
225  }
226 
227  if(!gpm.get())
228  return;
229 
230 //get selected layer
231  QVariant varLayer = m_ui->m_inputLayerComboBox->itemData(m_ui->m_inputLayerComboBox->currentIndex(), Qt::UserRole);
233 
234  std::unique_ptr<te::da::DataSetType> dataSetType = l->getSchema();
235  std::unique_ptr<te::da::DataSet> dataSet = l->getData();
236 
237 //create datasource to save the output information
238  std::string dataSetName = m_ui->m_newLayerNameLineEdit->text().toUtf8().data();
239 
240  std::size_t idx = dataSetName.find(".");
241  if (idx != std::string::npos)
242  dataSetName=dataSetName.substr(0,idx);
243 
244  te::da::DataSourcePtr outputDataSource;
245 
246  if(m_toFile)
247  {
248  outputDataSource = te::sa::CreateOGRDataSource(m_ui->m_repositoryLineEdit->text().toUtf8().data());
249  }
250  else
251  {
252  outputDataSource = te::da::GetDataSource(m_outputDatasource->getId());
253  }
254 
255  //run skater
257 
258  inParams->m_ds = std::move(dataSet);
259  inParams->m_dsType = std::move(dataSetType);
260  inParams->m_gpmAttrLink = gpm->getAttributeName();
261  inParams->m_gpm = std::move(gpm);
262 
263 
264  if(m_ui->m_clustersCheckBox->isChecked() && m_ui->m_popCheckBox->isChecked())
265  {
266  inParams->m_aggregType = te::sa::Both;
267  inParams->m_nClusters = (std::size_t)m_ui->m_nClustersLineEdit->text().toInt();
268  inParams->m_minPop = (std::size_t)m_ui->m_minPopLineEdit->text().toInt();
269  inParams->m_attrPop = m_ui->m_popComboBox->currentText().toUtf8().data();
270  }
271  else if(m_ui->m_clustersCheckBox->isChecked())
272  {
273  inParams->m_aggregType = te::sa::Clusters;
274  inParams->m_nClusters = (std::size_t)m_ui->m_nClustersLineEdit->text().toInt();
275  }
276  else if(m_ui->m_popCheckBox->isChecked())
277  {
278  inParams->m_aggregType = te::sa::Population;
279  inParams->m_minPop = (std::size_t)m_ui->m_minPopLineEdit->text().toInt();
280  inParams->m_attrPop = m_ui->m_popComboBox->currentText().toUtf8().data();
281  }
282 
283  inParams->m_attrs = attrs;
284 
286 
287  outParams->m_dataSource = outputDataSource;
288  outParams->m_outputDataSetName = dataSetName;
289 
290  int nClasses;
291 
292  //progress
294 
295  QApplication::setOverrideCursor(Qt::WaitCursor);
296 
297  try
298  {
300 
301  op.setParameters(inParams, outParams);
302 
303  op.execute();
304 
305  nClasses = op.getNumberOfClasses();
306  }
307  catch(const std::exception& e)
308  {
309  QMessageBox::warning(this, tr("Warning"), e.what());
310 
311  QApplication::restoreOverrideCursor();
312 
313  return;
314  }
315  catch(...)
316  {
317  QMessageBox::warning(this, tr("Warning"), tr("Internal Error. Skater not calculated."));
318 
319  QApplication::restoreOverrideCursor();
320 
321  return;
322  }
323 
324  QApplication::restoreOverrideCursor();
325 
326  //create layer
327  m_outputLayer = te::sa::CreateLayer(outputDataSource, dataSetName);
328 
329  //create legend
331 
332  accept();
333 }
334 
336 {
337  m_ui->m_newLayerNameLineEdit->clear();
338  m_ui->m_newLayerNameLineEdit->setEnabled(true);
339 
341  dlg.exec();
342 
343  std::list<te::da::DataSourceInfoPtr> dsPtrList = dlg.getSelecteds();
344 
345  if(dsPtrList.empty())
346  return;
347 
348  std::list<te::da::DataSourceInfoPtr>::iterator it = dsPtrList.begin();
349 
350  m_ui->m_repositoryLineEdit->setText(QString(it->get()->getTitle().c_str()));
351 
352  m_outputDatasource = *it;
353 
354  m_toFile = false;
355 }
356 
358 {
359  m_ui->m_newLayerNameLineEdit->clear();
360  m_ui->m_repositoryLineEdit->clear();
361 
362  QString fileName = QFileDialog::getSaveFileName(this, tr("Save as..."), QString(), tr("Shapefile (*.shp *.SHP);;"),nullptr, QFileDialog::DontConfirmOverwrite);
363 
364  if (fileName.isEmpty())
365  return;
366 
367  boost::filesystem::path outfile(fileName.toUtf8().data());
368 
369  m_ui->m_repositoryLineEdit->setText(outfile.string().c_str());
370 
371  m_ui->m_newLayerNameLineEdit->setText(outfile.leaf().string().c_str());
372 
373  m_ui->m_newLayerNameLineEdit->setEnabled(false);
374 
375  m_toFile = true;
376 }
377 
379 {
380  QString fileName = QFileDialog::getOpenFileName(this, tr("Open Generalized Proximity Matrix File"), "", tr("GAL Files (*.gal *.GAL);; GWT Files (*.gwt *.GWT)"));
381 
382  if(fileName.isEmpty())
383  return;
384 
385  //get selected layer
386  QVariant varLayer = m_ui->m_inputLayerComboBox->itemData(m_ui->m_inputLayerComboBox->currentIndex(), Qt::UserRole);
388  te::map::DataSetLayer* dsLayer = dynamic_cast<te::map::DataSetLayer*>(l.get());
389 
390  //check if the selected gpm is valid for selected layer
391  std::string path = fileName.toUtf8().data();
392  std::string dataSetName;
393  std::string attrName;
394 
396 
397  if(dsLayer->getDataSetName() != dataSetName)
398  {
399  QMessageBox::warning(this, tr("Warning"), tr("Invalid GPM file for selected layer."));
400  return;
401  }
402 
403  if(m_ui->m_attrLinkComboBox->currentText().toUtf8().data() != attrName)
404  {
405  QMessageBox::warning(this, tr("Warning"), tr("Invalid GPM file for selected Attr Link."));
406  return;
407  }
408 
409  m_ui->m_gpmLineEdit->setText(fileName);
410 }
411 
412 std::unique_ptr<te::sa::GeneralizedProximityMatrix> te::sa::SkaterDialog::loadGPM()
413 {
414  std::unique_ptr<te::sa::GeneralizedProximityMatrix> gpm;
415 
416  //get selected layer
417  QVariant varLayer = m_ui->m_inputLayerComboBox->itemData(m_ui->m_inputLayerComboBox->currentIndex(), Qt::UserRole);
419 
420  if(!l.get())
421  {
422  QMessageBox::warning(this, tr("Warning"), tr("Invalid selected layer."));
423  return gpm;
424  }
425 
426  te::map::DataSetLayer* dsLayer = dynamic_cast<te::map::DataSetLayer*>(l.get());
427 
428  //get gpm necessary parameters
430 
431  std::string dataSetName = dsLayer->getDataSetName();
432 
433  if(!m_ui->m_gpmGroupBox->isChecked())
434  {
435  //create gpm
436  if(QMessageBox::question(this, tr("Spatial Analysis"), tr("GPM not selected. Create default GPM?"), QMessageBox::No, QMessageBox::Yes) == QMessageBox::No)
437  return gpm;
438 
439  //get attrlink
440  std::unique_ptr<te::da::DataSetType> dsType = dsLayer->getSchema();
441 
442  if(!dsType->getPrimaryKey() || dsType->getPrimaryKey()->getProperties().empty())
443  {
444  QMessageBox::warning(this, tr("Warning"), tr("Invalid Data Set Primary Key."));
445  return gpm;
446  }
447 
448  std::string attrLink = dsType->getPrimaryKey()->getProperties()[0]->getName();
449 
450  //create default gpm
453 
454  te::sa::GPMBuilder builder(constructor, weights);
455 
456  builder.setGPMInfo(ds, dataSetName, attrLink);
457 
458  builder.build();
459 
460  gpm.reset(builder.getGPM());
461  }
462  else
463  {
464  if(m_ui->m_gpmLineEdit->text().isEmpty())
465  {
466  QMessageBox::warning(this, tr("Warning"), tr("GPM File not selected."));
467  return gpm;
468  }
469 
470  //load gpm
471  QFileInfo file(m_ui->m_gpmLineEdit->text());
472 
473  std::string extension = file.suffix().toUtf8().data();
474 
476 
477  if(extension == "gal" || extension == "GAL")
478  {
479  gpm.reset(swe.importFromGAL(m_ui->m_gpmLineEdit->text().toUtf8().data(), ds.get()));
480  }
481  else if(extension == "gwt" || extension == "GWT")
482  {
483  gpm.reset(swe.importFromGWT(m_ui->m_gpmLineEdit->text().toUtf8().data(), ds.get()));
484  }
485  }
486 
487  return gpm;
488 }
TEDATAACCESSEXPORT DataSourcePtr GetDataSource(const std::string &datasourceId, const bool opened=true)
Search for a data source with the informed id in the DataSourceManager.
void execute()
Function to execute the skater operation.
This class defines a an adjacency strategy class for a GPM constructor.
GeneralizedProximityMatrix * getGPM()
Function used to return the generated gpm.
Definition: GPMBuilder.cpp:91
std::vector< std::string > getOutputValues()
te::map::AbstractLayerPtr getOutputLayer()
boost::shared_ptr< DataSource > DataSourcePtr
TESAEXPORT te::da::DataSourcePtr CreateOGRDataSource(std::string repository)
bool setGPMInfo(te::da::DataSourcePtr ds, const std::string &dataSetName, const std::string &attributeName)
Function used to create an empty gpm (using a MEMORY DIRECT graph)
Definition: GPMBuilder.cpp:49
This class defines a class to calculates a weight for a GPM using No Weights strategy.
Class that represents the skater input parameters.
Definition: SkaterParams.h:56
void setLayers(std::list< te::map::AbstractLayerPtr > layers)
Set the layer that can be used.
std::unique_ptr< LayerSchema > getSchema() const
It returns the layer schema.
te::qt::widgets::DoubleListWidget * m_doubleListWidget
Widget used to select attributes.
Definition: SkaterDialog.h:90
static te::dt::Date ds(2010, 01, 01)
te::sa::GeneralizedProximityMatrix * importFromGAL(std::string pathFileName, te::da::DataSource *ds=0)
Function used to import a gpm from a Spatial Weights File GAL Format.
te::sa::GeneralizedProximityMatrix * importFromGWT(std::string pathFileName, te::da::DataSource *ds=0)
Function used to import a gpm from a Spatial Weights File GWT Format.
Class that represents the skater output parameters.
Definition: SkaterParams.h:98
te::da::DataSourceInfoPtr m_outputDatasource
Definition: SkaterDialog.h:92
Class used to execute the skater operations.
void setInputValues(std::vector< std::string > values)
void onTargetDatasourceToolButtonPressed()
A dialog for Spatial &#39;K&#39;luster Analysis by Tree Edge Removal.
URI C++ Library.
Definition: Attributes.h:37
void setParameters(te::sa::SkaterInputParams *inParams, te::sa::SkaterOutputParams *outParams)
std::unique_ptr< Ui::SkaterDialogForm > m_ui
Definition: SkaterDialog.h:88
Q_DECLARE_METATYPE(te::map::AbstractLayerPtr) te
static void getSpatialWeightsFileInfo(std::string pathFileName, std::string &dataSetName, std::string &attrName)
Function used to get information of how a Spatial Weights was generated.
Utility functions for the data access module.
std::string m_outputDataSetName
Attribute that defines the output dataset name.
Definition: SkaterParams.h:117
te::map::AbstractLayerPtr m_outputLayer
Generated Layer.
Definition: SkaterDialog.h:94
This class defines a an Abstract class for a GPM constructor.
This class defines a an Abstract class to calculates a weight for a GPM.
te::da::DataSourcePtr m_dataSource
Pointer to the output data source.
Definition: SkaterParams.h:115
const std::string & getDataSetName() const
const std::list< te::da::DataSourceInfoPtr > & getSelecteds() const
std::unique_ptr< te::sa::GeneralizedProximityMatrix > loadGPM()
TESAEXPORT te::map::AbstractLayerPtr CreateLayer(te::da::DataSourcePtr ds, std::string dataSetName)
A dialog for selecting a data source.
This class defines functions used to load and save gpm&#39;s using GAL and GWT formats, both formats use a &#39; &#39; as separator.
A layer with reference to a dataset.
Definition: DataSetLayer.h:47
This class defines the GPM Builder class.
Definition: GPMBuilder.h:54
TESAEXPORT void CreateSkaterGrouping(te::map::AbstractLayerPtr layer, int nClasses)
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
virtual const std::string & getDataSourceId() const
file(WRITE ${CMAKE_BINARY_DIR}/config_qhelp.cmake"configure_file (${TERRALIB_ABSOLUTE_ROOT_DIR}/doc/qhelp/help.qhcp.in ${CMAKE_BINARY_DIR}/share/terraview/help/help.qhcp @ONLY)") add_custom_command(OUTPUT del_dir COMMAND $
void onInputLayerComboBoxActivated(int index)
void onTargetFileToolButtonPressed()