CheckGeomValidityDialog.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/vp/qt/CheckGeomValidityDialog.cpp
22 
23 \brief A dialog used to check geometries validity.
24 */
25 
26 // TerraLib
27 #include "../../dataaccess/dataset/ObjectId.h"
28 #include "../../dataaccess/datasource/DataSourceCapabilities.h"
29 #include "../../dataaccess/utils/Utils.h"
30 #include "../../geometry/Geometry.h"
31 #include "../../geometry/Utils.h"
32 #include "../../qt/widgets/canvas/Canvas.h"
33 #include "../../qt/widgets/Utils.h"
34 #include "../../qt/widgets/progress/ProgressViewerDialog.h"
35 #include "../MakeGeometryValid.h"
36 #include "../Utils.h"
37 #include "ui_CheckGeomValidityDialogForm.h"
39 
40 // Boost
41 #include <boost/lexical_cast.hpp>
42 
43 // Qt
44 #include <QMessageBox>
45 #include <QPointF>
46 #include <QTableWidget>
47 #include <QTableWidgetItem>
48 
50 Q_DECLARE_METATYPE(te::gm::TopologyValidationError)
51 
52 te::vp::CheckGeomValidityDialog::CheckGeomValidityDialog(QWidget* parent, Qt::WindowFlags f)
53  : QDialog(parent, f),
54  m_ui(new Ui::CheckGeomValidityDialogForm),
55  m_mapDisplay(nullptr),
56  m_drawMark(false)
57 {
58  m_ui->setupUi(this);
59 
60  m_ui->m_invalidTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
61  m_ui->m_invalidTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
62  m_ui->m_invalidTableWidget->horizontalHeader()->setStretchLastSection(true);
63 
64  connect(m_ui->m_verifyPushButton, SIGNAL(clicked()), this, SLOT(onVerifyPushButtonClicked()));
65  connect(m_ui->m_fixPushButton, SIGNAL(clicked()), this, SLOT(onFixPushButtonClicked()));
66  connect(m_ui->m_invalidTableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(onTableWidgetItemDoubleClicked(QTableWidgetItem*)));
67 
68  m_ui->m_helpPushButton->setPageReference("widgets/utils/check_geometry_validity.html");
69 }
70 
72 {
73  m_mapDisplay->getDraftPixmap()->fill(Qt::transparent);
74 }
75 
76 void te::vp::CheckGeomValidityDialog::setLayers(std::list<te::map::AbstractLayerPtr> layers, te::map::AbstractLayerPtr selectedLayer)
77 {
78  for (std::list<te::map::AbstractLayerPtr>::iterator it = layers.begin(); it != layers.end(); ++it)
79  {
80  if(it->get()->isValid() && !it->get()->getSchema()->hasRaster())
81  m_ui->m_layersComboBox->addItem(it->get()->getTitle().c_str(), QVariant::fromValue(*it));
82  }
83 
84  if (selectedLayer)
85  {
86  int index = m_ui->m_layersComboBox->findText(QString::fromUtf8(selectedLayer->getTitle().c_str()));
87  m_ui->m_layersComboBox->setCurrentIndex(index);
88  }
89 }
90 
92 {
93  if (m_ui->m_layersComboBox->count() < 1)
94  return;
95 
96  m_ui->m_invalidTableWidget->setRowCount(0);
97 
98  QVariant var = m_ui->m_layersComboBox->itemData(m_ui->m_layersComboBox->currentIndex(), Qt::UserRole);
100 
101  std::unique_ptr<te::da::DataSetType> schema = m_currentLayer->getSchema();
102  std::unique_ptr<te::da::DataSet> data = m_currentLayer->getData();
103 
104  te::da::PrimaryKey* pk = schema->getPrimaryKey();
105 
106  QStringList list;
107 
108  if (pk)
109  {
110  std::string propertyName = pk->getProperties()[0]->getName();
111  std::size_t propertyPosition = schema->getPropertyPosition(propertyName);
112  int propertyType = pk->getProperties()[0]->getType();
113 
114  m_oidSet.reset(new te::da::ObjectIdSet());
115  m_oidSet->addProperty(propertyName, propertyPosition, propertyType);
116 
117  list.append(propertyName.c_str());
118  }
119 
120  list.append(tr("Message"));
121 
122  m_ui->m_invalidTableWidget->setColumnCount(list.size());
123  m_ui->m_invalidTableWidget->setHorizontalHeaderLabels(list);
124 
125  std::size_t pos = te::da::GetFirstSpatialPropertyPos(data.get());
126 
127  //progress
128  std::size_t size = data->size();
130 
131  te::common::TaskProgress task("Checking...");
132  task.setTotalSteps((int)size);
133 
134  data->moveBeforeFirst();
135 
136  int count = 0;
137 
138  while (data->moveNext())
139  {
140  if (task.isActive())
141  {
142  task.pulse();
143  }
144  else
145  {
146  break;
147  }
148 
149  try
150  {
151  if (data->isNull(pos))
152  continue;
153 
154  std::unique_ptr<te::gm::Geometry> geom = data->getGeometry(pos);
155 
157  bool isValid = te::gm::CheckValidity(geom.get(), err);
158 
159  if (!isValid)
160  {
161  m_ui->m_invalidTableWidget->insertRow(count);
162 
163  QTableWidgetItem *msgItem = new QTableWidgetItem(err.m_message.c_str());
164  msgItem->setData(Qt::UserRole, QVariant::fromValue(err));
165  msgItem->setFlags(Qt::ItemIsEnabled);
166 
167  if (pk)
168  {
169  // Object id set is used to fix geometries.
171  oid->addValue(data->getValue(pk->getProperties()[0]->getName())->clone());
172  m_oidSet->add(oid);
173 
174  QTableWidgetItem *idItem = new QTableWidgetItem(data->getAsString(pk->getProperties()[0]->getName()).c_str());
175  idItem->setFlags(Qt::ItemIsEnabled);
176 
177  m_ui->m_invalidTableWidget->setItem(count, 0, idItem);
178  }
179 
180  m_ui->m_invalidTableWidget->setItem(count, 1, msgItem);
181 
182  ++count;
183  }
184  }
185  catch(te::common::Exception& e)
186  {
187  m_ui->m_invalidTableWidget->insertRow(count);
188 
189  QTableWidgetItem *msgItem = new QTableWidgetItem(e.what());
190  msgItem->setFlags(Qt::NoItemFlags);
191 
192  if (pk)
193  {
194  QTableWidgetItem *idItem = new QTableWidgetItem(data->getAsString(pk->getProperties()[0]->getName()).c_str());
195  idItem->setFlags(Qt::NoItemFlags);
196 
197  m_ui->m_invalidTableWidget->setItem(count, 0, idItem);
198  }
199 
200  m_ui->m_invalidTableWidget->setItem(count, 1, msgItem);
201 
202  ++count;
203  }
204  }
205 
206  if(count > 0)
207  m_ui->m_fixPushButton->setEnabled(true);
208  else
209  m_ui->m_fixPushButton->setEnabled(false);
210 }
211 
213 {
214  QApplication::setOverrideCursor(Qt::WaitCursor);
215 
216  te::da::DataSourcePtr dataSource =
217  te::da::GetDataSource(m_currentLayer->getDataSourceId(), true);
218 
219  std::string errorMessage;
220 
221  try
222  {
224 
225  bool success = false;
226 
228  dataSource, m_currentLayer->getDataSetName(), errorMessage,
229  m_oidSet.get());
230 
231  if(!success)
232  {
233  QApplication::setOverrideCursor(Qt::ArrowCursor);
234 
235  QMessageBox::warning(this, tr("Check Geometry Validity"), errorMessage.c_str());
236  m_ui->m_verifyPushButton->setFocus();
237  m_ui->m_fixPushButton->setEnabled(false);
238 
239  return;
240  }
241  }
242  catch (const std::exception& e)
243  {
244  QApplication::setOverrideCursor(Qt::ArrowCursor);
245 
246  QMessageBox::warning(this, tr("Check Geometry Validity"), e.what());
247  m_ui->m_verifyPushButton->setFocus();
248  m_ui->m_fixPushButton->setEnabled(false);
249 
250  return;
251  }
252 
253  m_ui->m_invalidTableWidget->setRowCount(0);
254 
255  QApplication::setOverrideCursor(Qt::ArrowCursor);
256 
257  if(errorMessage.empty())
258  {
259  QMessageBox::information(this, tr("Check Geometry Validity"), tr("The fix was concluded successfully. Verify the layer again!"));
260  }
261  else
262  {
263  QMessageBox::information(this, tr("Check Geometry Validity"), tr("The operation was concluded. But some warnings had occurred.") + QString(errorMessage.c_str()));
264  }
265 
266  m_ui->m_verifyPushButton->setFocus();
267  m_ui->m_fixPushButton->setEnabled(false);
268 }
269 
271 {
272  const te::gm::Envelope& currEnv = m_mapDisplay->getExtent();
273 
274  double auxX = (currEnv.m_urx - currEnv.m_llx) / 2;
275  double auxY = (currEnv.m_ury - currEnv.m_lly) / 2;
276 
277  int row = item->row();
278 
279  QVariant var;
280 
281  if(m_ui->m_invalidTableWidget->columnCount() == 1)
282  var = m_ui->m_invalidTableWidget->item(row, 0)->data(Qt::UserRole);
283  else
284  var = m_ui->m_invalidTableWidget->item(row, 1)->data(Qt::UserRole);
285 
287 
288  m_currentCoord.reset(new te::gm::Point(err.m_coordinate.x, err.m_coordinate.y, m_currentLayer->getSRID()));
289 
290  if (m_mapDisplay->getSRID() == 0)
291  m_mapDisplay->setSRID(m_currentLayer->getSRID());
292 
293  try
294  {
295  if (m_currentLayer->getSRID() != m_mapDisplay->getSRID())
296  m_currentCoord->transform(m_mapDisplay->getSRID());
297  }
298  catch (const std::exception & e)
299  {
300  m_currentCoord.reset(nullptr);
301  QMessageBox::warning(this, tr("Check Geometry Validity"), e.what());
302  return;
303  }
304 
305  te::gm::Envelope env;
306  env.m_llx = m_currentCoord->getX() - auxX;
307  env.m_lly = m_currentCoord->getY() - auxY;
308  env.m_urx = m_currentCoord->getX() + auxX;
309  env.m_ury = m_currentCoord->getY() + auxY;
310 
311  m_mapDisplay->setExtent(env, true);
312 }
313 
315 {
316  m_mapDisplay = md;
317 
318  connect(m_mapDisplay, SIGNAL(extentChanged()), this, SLOT(onExtentChanged()));
319  connect(m_mapDisplay, SIGNAL(displayPaintEvent(QPainter*)), this, SLOT(onDisplayPaintEvent(QPainter*)));
320 }
321 
323 {
324  drawMark();
325 }
326 
328 {
329  if (!m_currentCoord)
330  return;
331 
332  m_markPixmap.reset(new QPixmap(m_mapDisplay->width(), m_mapDisplay->height()));
333  m_markPixmap->fill(Qt::transparent);
334 
335  const te::gm::Envelope& env = m_mapDisplay->getExtent();
336 
338  canvas->setDevice(m_markPixmap.get(), false);
339  canvas->setWindow(env.m_llx, env.m_lly, env.m_urx, env.m_ury);
340 
341  QMatrix matrix = canvas->getMatrix();
342  QPointF pointCanvas = matrix.map(QPointF(m_currentCoord->getX(), m_currentCoord->getY()));
343 
344  QPointF llCanvas;
345  llCanvas.setX(pointCanvas.x() - 10);
346  llCanvas.setY(pointCanvas.y() - 10);
347 
348  QPointF urCanvas;
349  urCanvas.setX(pointCanvas.x() + 10);
350  urCanvas.setY(pointCanvas.y() + 10);
351 
352  QPointF llGeo = matrix.inverted().map(llCanvas);
353  QPointF urGeo = matrix.inverted().map(urCanvas);
354 
355  te::gm::Envelope mark(llGeo.x(), llGeo.y(), urGeo.x(), urGeo.y());
356 
357  te::gm::Geometry* newGeom = te::gm::GetGeomFromEnvelope(&mark, m_currentLayer->getSRID());
358 
359  te::qt::widgets::Config2DrawPolygons(canvas, QColor(0, 0, 0, 0), QColor(0, 255, 0, 255), 4);
360 
361  canvas->draw(newGeom);
362 
363  //m_mapDisplay->repaint();
364 
365  m_drawMark = true;
366 
367  delete newGeom;
368  delete canvas;
369 }
370 
372 {
373  if (!m_drawMark)
374  return;
375 
376  QImage img = m_markPixmap->toImage();
377 
378  const te::gm::Envelope& env = m_mapDisplay->getExtent();
379  int envWidth = env.m_urx - env.m_llx;
380  int envHeight = env.m_ury - env.m_lly;
381 
382  painter->setOpacity(Qt::transparent);
383  painter->drawImage(0, 0, img, 0, 0, envWidth, envHeight);
384 }
A dialog used to check geometries validity.
TEDATAACCESSEXPORT DataSourcePtr GetDataSource(const std::string &datasourceId, const bool opened=true)
Search for a data source with the informed id in the DataSourceManager.
void setDevice(QPaintDevice *device, bool takeOwnerShip)
It sets new device as QPrinter.
double y
y-coordinate.
Definition: Coord2D.h:114
boost::shared_ptr< DataSource > DataSourcePtr
double x
x-coordinate.
Definition: Coord2D.h:113
virtual const char * what() const
It outputs the exception message.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
double m_urx
Upper right corner x-coordinate.
std::unique_ptr< te::gm::Point > m_currentCoord
A widget to control the display of a set of layers.
void addValue(te::dt::AbstractData *data)
It adds a property value to uniquely identify a data set element.
void draw(const te::gm::Geometry *geom)
It draws the geometry on canvas.
bool isActive() const
Verify if the task is active.
te::qt::widgets::MapDisplay * m_mapDisplay
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the primary key.
Definition: PrimaryKey.h:109
std::unique_ptr< Ui::CheckGeomValidityDialogForm > m_ui
void setTotalSteps(int value)
Set the task total stepes.
QMatrix getMatrix()
It returns the matrix.
TEQTWIDGETSEXPORT void Config2DrawPolygons(te::map::Canvas *canvas, const QColor &fillColor, const QColor &contourColor, const std::size_t &contourWidth=1)
It configs (i.e. prepares) the given canvas to draw polygons.
void setWindow(const double &llx, const double &lly, const double &urx, const double &ury)
It sets the world (or window) coordinates area (supposing a cartesian reference system).
double m_llx
Lower left corner x-coordinate.
TEDATAACCESSEXPORT std::size_t GetFirstSpatialPropertyPos(const te::da::DataSet *dataset)
It returns the first dataset spatial property or NULL if none is found.
A point with x and y coordinate values.
Definition: Point.h:50
An Envelope defines a 2D rectangular region.
void ObjectId()
ObjectId example.
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
virtual int getSRID() const
It return the Spatial Reference System used by the Map Display.
This class represents an unique id for a data set element.
URI C++ Library.
Definition: Attributes.h:37
Q_DECLARE_METATYPE(te::map::AbstractLayerPtr) Q_DECLARE_METATYPE(te
virtual const te::gm::Envelope & getExtent() const
It returns the world extent showned by the MapDisplay.
void pulse()
Calls setCurrentStep() function using getCurrentStep() + 1.
void setLayers(std::list< te::map::AbstractLayerPtr > layers, te::map::AbstractLayerPtr selectedLayer=0)
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
static bool makeValid(const te::da::DataSourcePtr dataSource, const std::string &dataSetName, std::string &errorMessage, te::da::ObjectIdSet *oidSet=0)
This method gets the datasource capabilities and calls the specific function to fix geometry...
te::map::AbstractLayerPtr m_currentLayer
double m_lly
Lower left corner y-coordinate.
void setMapDisplay(te::qt::widgets::MapDisplay *md)
virtual QPixmap * getDraftPixmap() const
It returns the map display draft pixmap.
double m_ury
Upper right corner y-coordinate.
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
TEGEOMEXPORT bool CheckValidity(const Geometry *geom, te::gm::TopologyValidationError &error)
It check geometry validity using GEOS.
virtual void setSRID(const int &srid, bool doRefresh=true)
It sets a new Spatial Reference System to be used by the Map Display.
void onTableWidgetItemDoubleClicked(QTableWidgetItem *item)
This struct contains informations about GEOS TopologyValidationError.
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
std::unique_ptr< te::da::ObjectIdSet > m_oidSet
virtual void setExtent(te::gm::Envelope &e, bool doRefresh=true)
It sets the world visible area and refreshes the contents in the map display.
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
std::unique_ptr< QPixmap > m_markPixmap