MakeGeometryValid.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 FixGeometry.cpp
22  */
23 
24 #include "../common/progress/TaskProgress.h"
25 #include "../core/logger/Logger.h"
26 #include "../core/translator/Translator.h"
27 #include "../dataaccess/dataset/DataSet.h"
28 #include "../dataaccess/query/DataSetName.h"
29 #include "../dataaccess/query/EqualTo.h"
30 #include "../dataaccess/query/Field.h"
31 #include "../dataaccess/query/Fields.h"
32 #include "../dataaccess/query/From.h"
33 #include "../dataaccess/query/FromItem.h"
34 #include "../dataaccess/query/LiteralString.h"
35 #include "../dataaccess/query/PropertyName.h"
36 #include "../dataaccess/query/Select.h"
37 #include "../dataaccess/query/ST_Buffer.h"
38 #include "../dataaccess/query/ST_IsValid.h"
39 #include "../dataaccess/query/ST_MakeValid.h"
40 #include "../dataaccess/query/ST_Multi.h"
41 #include "../dataaccess/query/Where.h"
42 
43 #include "../dataaccess/datasource/DataSourceCapabilities.h"
44 #include "../dataaccess/datasource/DataSourceTransactor.h"
45 
46 #include "../dataaccess/utils/Utils.h"
47 
48 #include "../geometry/FixGeometryTopology.h"
49 #include "../geometry/Geometry.h"
50 #include "../geometry/GeometryProperty.h"
51 #include "../geometry/Utils.h"
52 
53 #include "../memory/DataSet.h"
54 #include "../memory/DataSetItem.h"
55 
56 #include "MakeGeometryValid.h"
57 #include "Utils.h"
58 
59 #include "boost/lexical_cast.hpp"
60 
62  const std::string &dataSetName,
63  std::string& errorMessage,
64  te::da::ObjectIdSet* oidSet)
65 {
66  const te::da::DataSourceCapabilities dsCapabilities = dataSource->getCapabilities();
68 
69  if(queryCapabilities.supportsSpatialSQLDialect())
70  return makeValidQuery(dataSource, dataSetName, errorMessage, oidSet);
71  else
72  return makeValidMemory(dataSource, dataSetName, errorMessage, oidSet);
73 }
74 
76  const te::da::DataSourcePtr dataSource, const std::string& dataSetName,
77  std::string& errorMessage, da::ObjectIdSet* /*oidSet*/)
78 {
79  // Creating and executing a query to fix geometries.
80  //
81  // NOTE: This code creates and executes a query using ST_MakeValid clause.
82  // The result is a te::da::DataSet with same attributes from input table
83  // plus fixed geometries.
84  //
85 
86  std::unique_ptr<te::da::DataSetType> dsType(
87  te::da::GetDataSetType(dataSetName, dataSource->getId()));
88 
89  te::gm::GeometryProperty* geometryProperty =
90  te::da::GetFirstGeomProperty(dsType.get());
91 
92  te::da::Fields fields;
93 
94  std::vector<te::dt::Property*> props = dsType->getProperties();
95  for(std::size_t p = 0; p < props.size(); ++p)
96  {
97  if(props[p]->getType() == te::dt::GEOMETRY_TYPE)
98  continue;
99 
100  te::da::Field* field = new te::da::Field(props[p]->getName());
101  fields.push_back(field);
102  }
103 
104  te::da::ST_MakeValid st_makeValid(
105  te::da::PropertyName(geometryProperty->getName()));
106  te::da::Expression* e_makeValid = new te::da::ST_MakeValid(st_makeValid);
107 
108  te::da::Expression* e_buffer = new te::da::ST_Buffer(*e_makeValid, 0);
109 
110  te::da::Field* f_geometry;
111 
112  if(te::gm::IsMultiType(geometryProperty->getGeometryType()))
113  {
114  te::da::Expression* e_multi = new te::da::ST_Multi(*e_buffer);
115  f_geometry = new te::da::Field(*e_multi, geometryProperty->getName());
116  }
117  else
118  {
119  f_geometry = new te::da::Field(*e_buffer, geometryProperty->getName());
120  }
121 
122  fields.push_back(f_geometry);
123 
124  te::da::From from;
125  te::da::FromItem* fromItem = new te::da::DataSetName(dataSetName);
126  from.push_back(fromItem);
127 
128  te::da::ST_IsValid st_isValid(
129  te::da::PropertyName(geometryProperty->getName()));
130  te::da::Expression* e_isValid = new te::da::ST_IsValid(st_isValid);
131 
132  te::da::Expression* e_false = new te::da::LiteralString("f");
133 
134  te::da::EqualTo equal(e_isValid, e_false);
135 
136  te::da::Where where(equal);
137 
138  te::da::Select select(fields, from, where);
139 
140  std::unique_ptr<te::da::DataSet> ds;
141 
142  try
143  {
144  ds.reset(dataSource->query(select).release());
145  }
146  catch (const te::common::Exception& e)
147  {
148  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
149  TE_TR("Fix Geometry") + ": " + e.what());
150 
151  errorMessage = e.what();
152  return false;
153  }
154  catch (const std::exception& e)
155  {
156  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
157  TE_TR("Fix Geometry") + ": " + e.what());
158 
159  errorMessage = e.what();
160  return false;
161  }
162  catch (...)
163  {
164  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
165  TE_TR("Fix Geometry") + ": Unknown Excption.");
166 
167  errorMessage = "Unknown Excption.";
168  return false;
169  }
170 
171 
172  // Updating input table.
173  //
174  // NOTE: This code uptades the invalid geometries.
175  //
176 
177  // Get position of attr used as pk
178  te::da::PrimaryKey* pk = dsType->getPrimaryKey();
179 
180  size_t numProps = pk->getProperties().size();
181  std::vector<std::size_t> ids;
182 
183  for (size_t i = 0; i < numProps; ++i)
184  {
185  std::string propName = pk->getProperties()[i]->getName();
186  ids.push_back(dsType->getPropertyPosition(propName));
187  }
188 
189  std::set<int> posSet;
190  posSet.insert((int)dsType->getPropertyPosition(geometryProperty->getName()));
191  std::vector< std::set<int> > propsPos;
192 
193  for(std::size_t p = 0; p < ds->size(); ++p)
194  propsPos.push_back(posSet);
195 
196  std::unique_ptr<te::da::DataSourceTransactor> transactor =
197  dataSource->getTransactor();
198 
199  try
200  {
201  transactor->update(dataSetName, ds.get(), propsPos, ids);
202  }
203  catch (const te::common::Exception& e)
204  {
205  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
206  TE_TR("Fix Geometry") + ": " + e.what());
207 
208  errorMessage = e.what();
209 
210  transactor->rollBack();
211  return false;
212  }
213  catch (const std::exception& e)
214  {
215  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
216  TE_TR("Fix Geometry") + ": " + e.what());
217 
218  errorMessage = e.what();
219 
220  transactor->rollBack();
221  return false;
222  }
223  catch (...)
224  {
225  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
226  TE_TR("Fix Geometry") + ": Unknown Excption.");
227 
228  errorMessage = "Unknown Excption.";
229 
230  transactor->rollBack();
231  return false;
232  }
233 
234  transactor->commit();
235 
236  return true;
237 }
238 
240  const std::string& dataSetName,
241  std::string& errorMessage,
242  te::da::ObjectIdSet* oidSet)
243 {
244  std::unique_ptr<te::da::DataSourceTransactor> transactor =
245  dataSource->getTransactor();
246 
247  std::unique_ptr<te::da::DataSetType> dataSetType(
248  te::da::GetDataSetType(dataSetName, dataSource->getId()));
249 
250  te::gm::GeometryProperty* geometryProperty =
251  te::da::GetFirstGeomProperty(dataSetType.get());
252 
253  std::unique_ptr<te::da::DataSet> dataSetToFix;
254  std::unique_ptr<te::mem::DataSet> fixedDataSet(new te::mem::DataSet(dataSetType.get()));
255 
256  try
257  {
258  // Get the object id properties.
259  std::vector<std::string> oidprops;
260  te::da::GetOIDPropertyNames(dataSetType.get(), oidprops);
261 
262  // Get dataSet.
263  if(oidSet && oidSet->size() > 0) // Based on Object Id Set.
264  {
265  dataSetToFix = dataSource->getDataSet(dataSetName, oidSet);
266  oidSet->clear();
267  }
268  else
269  {
270  dataSetToFix = dataSource->getDataSet(dataSetName);
271  }
272 
273  oidSet = new te::da::ObjectIdSet();
274 
275  // Scrolls through the dataset.
276  dataSetToFix->moveBeforeFirst();
277 
278  te::common::TaskProgress task("Fixing...");
279  task.setTotalSteps((int)dataSetToFix->size());
280 
281  while(dataSetToFix->moveNext())
282  {
283  if (!task.isActive())
284  {
285  errorMessage = TE_TR("Fix geometry canceled!");
286  return false;
287  }
288 
289  task.pulse();
290 
291  std::unique_ptr<te::gm::Geometry> geometryToFix =
292  dataSetToFix->getGeometry(geometryProperty->getName());
293 
294  std::vector<te::gm::Geometry*> fixedGeometryVec;
295 
296  te::gm::TopologyValidationError topologyError;
297 
298  bool isValid = te::gm::CheckValidity(geometryToFix.get(), topologyError);
299 
300  if(!isValid)
301  {
302  isValid = te::gm::FixGeometryTopology::fixTopology(*geometryToFix.get(), fixedGeometryVec, topologyError);
303 
304  if(!isValid)
305  {
306  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
307  TE_TR("Fix Geometry") + ": " +
308  TE_TR("Could not fix geometry") + ": " + topologyError.m_message + "; " +
309  TE_TR("Coordinate") + ": (" + boost::lexical_cast<std::string>(topologyError.m_coordinate.getX()) + "," +
310  boost::lexical_cast<std::string>(topologyError.m_coordinate.getY()) + "); " +
311  TE_TR("Geometry WKT") + ": " + geometryToFix->asText());
312 
313  errorMessage = "Some geometries could not be fixed. Check the log file for more information.";
314 
315  continue;
316  }
317 
318  for(std::size_t i = 0; i < fixedGeometryVec.size(); ++i)
319  {
320  te::mem::DataSetItem* dataSetItemMemory = GetFilledItemMemory(dataSetToFix.get());
321 
322  dataSetItemMemory->setGeometry(geometryProperty->getName(), fixedGeometryVec[i]);
323 
324  fixedDataSet->add(dataSetItemMemory);
325  }
326 
327  // Add the current object id, to remove from input dataset.
328  te::da::ObjectId* oid = te::da::GenerateOID(dataSetToFix.get(), oidprops);
329  oidSet->add(oid);
330 
331  for (std::string p : oidprops)
332  {
333  te::dt::Property* prop = dataSetType->getProperty(p);
334  oidSet->addProperty(p, te::da::GetPropertyPos(dataSetType.get(), p), prop->getType());
335  }
336 
337  }
338  }
339 
340  std::map<std::string, std::string> options;
341 
342  transactor->remove(dataSetName, oidSet);
343  transactor->add(dataSetName, fixedDataSet.get(), options);
344  }
345  catch (const te::common::Exception& e)
346  {
347  std::unique_ptr<te::gm::Geometry> geometryToFix = dataSetToFix->getGeometry(geometryProperty->getName());
348 
349  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
350  TE_TR("Fix Geometry") + ": " +
351  TE_TR("Could not fix geometry") + ": " + e.what() + "; " +
352  TE_TR("Geometry WKT") + ": " + geometryToFix->asText());
353 
354  errorMessage = e.what();
355  return false;
356  }
357  catch (const std::exception& e)
358  {
359  std::unique_ptr<te::gm::Geometry> geometryToFix = dataSetToFix->getGeometry(geometryProperty->getName());
360 
361  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
362  TE_TR("Fix Geometry") + ": " +
363  TE_TR("Could not fix geometry") + ": " + e.what() + "; " +
364  TE_TR("Geometry WKT") + ": " + geometryToFix->asText());
365 
366  errorMessage = e.what();
367  return false;
368  }
369  catch (...)
370  {
371  std::unique_ptr<te::gm::Geometry> geometryToFix = dataSetToFix->getGeometry(geometryProperty->getName());
372 
373  TE_LOG_ERROR(TE_TR("Vector Processing") + " - " +
374  TE_TR("Fix Geometry") + ": " +
375  TE_TR("Could not fix geometry") + ": Unknown Excption; " +
376  TE_TR("Geometry WKT") + ": " + geometryToFix->asText());
377 
378  errorMessage = "Unknown Excption.";
379  return false;
380  }
381 
382  return true;
383 }
Geometric property.
void setGeometry(std::size_t i, te::gm::Geometry *value)
It sets the value of the i-th property.
An abstract class that models a source of data in a query.
Definition: FromItem.h:50
The Field class can be used to model an expression that takes part of the output items of a SELECT...
TEDATAACCESSEXPORT ObjectId * GenerateOID(DataSet *dataset, const std::vector< std::string > &names)
A class that models the name of a dataset used in a From clause.
Definition: DataSetName.h:43
boost::shared_ptr< DataSource > DataSourcePtr
A class that models the name of any property of an object.
virtual const char * what() const
It outputs the exception message.
Spatial multi operator.
Definition: ST_Multi.h:50
static bool makeValidMemory(const te::da::DataSourcePtr dataSource, const std::string &dataSetName, std::string &errorMessage, te::da::ObjectIdSet *oidSet=0)
It tries to fix invalid geometry by GEOS and updates the source data.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
TEDATAACCESSEXPORT std::size_t GetPropertyPos(const DataSet *dataset, const std::string &name)
TEGEOMEXPORT bool IsMultiType(te::gm::GeomType geomType)
Verifies if the geomType is a collection type.
te::da::QueryCapabilities queryCapabilities
A class that represents the known capabilities of a specific data source, i.e. this class informs all...
double getY() const
It returns the y-coordinate.
Definition: Coord2D.h:108
static te::dt::Date ds(2010, 01, 01)
void addProperty(const std::string &name, std::size_t pos, int type)
It adds a property that will be used to generate the unique ids.
Definition: ObjectIdSet.cpp:75
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
const QueryCapabilities & getQueryCapabilities() const
It models a property definition.
Definition: Property.h:59
bool isActive() const
Verify if the task is active.
This is an abstract class that models a query expression.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the primary key.
Definition: PrimaryKey.h:109
void setTotalSteps(int value)
Set the task total stepes.
Implementation of a random-access dataset class for the TerraLib In-Memory Data Access driver...
A class that informs the query support of a given data source.
Spatial Buffer operator.
Definition: ST_Buffer.h:51
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
This class represents an unique id for a data set element.
std::size_t size() const
It returns the object id set size.
Spatial operator that tries to make geometry valid.
Definition: ST_MakeValid.h:50
GeomType getGeometryType() const
It returns the geometry subtype allowed for the property.
boost::ptr_vector< Field > Fields
Fields is just a boost::ptr_vector of Field pointers.
Definition: Fields.h:37
A class that can be used to model a filter expression that can be applied to a query.
Definition: Where.h:47
te::gm::Polygon * p
void pulse()
Calls setCurrentStep() function using getCurrentStep() + 1.
bool supportsSpatialSQLDialect() const
Utility functions for the data access module.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
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...
A Select models a query to be used when retrieving data from a DataSource.
Definition: Select.h:65
boost::ptr_vector< FromItem > From
It models the FROM clause for a query.
Definition: From.h:37
int getType() const
It returns the property data type.
Definition: Property.h:161
An implementation of the DatasetItem class for the TerraLib In-Memory Data Access driver...
double getX() const
It returns the x-coordinate.
Definition: Coord2D.h:102
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
static bool makeValidQuery(const te::da::DataSourcePtr dataSource, const std::string &dataSetName, std::string &errorMessage, te::da::ObjectIdSet *oidSet=0)
It tries to fix invalid geometry by SQL clause ST_MakeValid and updates the source data...
It models the comparison operator.
Definition: EqualTo.h:46
static bool fixTopology(const te::gm::Geometry &geometry, std::vector< te::gm::Geometry * > &fixedGeometryVector, TopologyValidationError topologyError)
This method gets a topologically inconsistent geometry and calls specific functions to fix this geome...
void clear()
It clears this object id set.
TEGEOMEXPORT bool CheckValidity(const Geometry *geom, te::gm::TopologyValidationError &error)
It check geometry validity using GEOS.
TEVPEXPORT te::mem::DataSetItem * GetFilledItemMemory(te::da::DataSet *dataSet)
It returns a memory item with all properties filled with values from the current position dataset...
#define TE_LOG_ERROR(message)
Use this tag in order to log a message to the TerraLib default logger with the ERROR level...
Definition: Logger.h:337
TEDATAACCESSEXPORT void GetOIDPropertyNames(const DataSetType *type, std::vector< std::string > &pnames)
void add(ObjectId *oid)
It adds an object id to this object id set.
Definition: ObjectIdSet.cpp:83
TEDATAACCESSEXPORT DataSetType * GetDataSetType(const std::string &name, const std::string &datasourceId)
Spatial is valid operator.
Definition: ST_IsValid.h:50
TEDATAACCESSEXPORT te::gm::GeometryProperty * GetFirstGeomProperty(const DataSetType *dt)
This struct contains informations about GEOS TopologyValidationError.
Functions to make geometry valid.
This class models a string Literal value.
Definition: LiteralString.h:46
const std::string & getName() const
It returns the property name.
Definition: Property.h:127