MergeGeometriesTool.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2001-2009 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/edit/qt/tools/MergeGeometriesTool.cpp
22 
23  \brief This class implements a concrete tool to merge polygons.
24 */
25 
26 // TerraLib
27 #include "../../../common/STLUtils.h"
28 #include "../../../geometry/Envelope.h"
29 #include "../../../geometry/MultiPolygon.h"
30 #include "../../../geometry/Point.h"
31 #include "../../../geometry/Utils.h"
32 #include "../../../qt/widgets/canvas/MapDisplay.h"
33 #include "../../../qt/widgets/Utils.h"
34 #include "../../../dataaccess/utils/Utils.h"
35 #include "../../Feature.h"
36 #include "../../RepositoryManager.h"
37 #include "../../Utils.h"
38 #include "../Renderer.h"
39 #include "../Utils.h"
40 #include "../core/command/AddCommand.h"
41 #include "../core/UndoStackManager.h"
42 #include "MergeGeometriesTool.h"
43 
44 // Qt
45 #include <QMessageBox>
46 #include <QMouseEvent>
47 #include <QPainter>
48 #include <QPixmap>
49 #include <QInputDialog>
50 
51 // STL
52 #include <cassert>
53 #include <memory>
54 
56  : GeometriesUpdateTool(display, layer.get(), parent),
57  m_gc(new te::gm::GeometryCollection(0, te::gm::MultiPolygonType, m_layer->getSRID())),
58  m_oidSet(nullptr)
59 {
60  setCursor(cursor);
61 
63 }
64 
66 {
67  //Removes from the repository
68  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator it;
69  for (it = m_oidSet->begin(); it != m_oidSet->end(); ++it)
70  {
71  if (RepositoryManager::getInstance().hasIdentify(m_layer->getId(), (*it)))
72  RepositoryManager::getInstance().removeFeature(m_layer->getId(), (*it));
73  }
74 
75  delete m_oidSet;
76 }
77 
79 {
80  try
81  {
82  te::gm::Geometry* geom = nullptr;
83 
84  const te::da::ObjectIdSet* objSet = m_layer->getSelected();
85 
86  std::unique_ptr<te::da::DataSet> ds(m_layer->getData(objSet));
87 
88  std::unique_ptr<te::da::DataSetType> dt(m_layer->getSchema()) ;
89 
91 
92  if (m_oidSet == nullptr)
94 
95  while (ds->moveNext())
96  m_gc->add(dynamic_cast<te::gm::Geometry*>(ds->getGeometry(geomProp->getName()).release()));
97 
99  {
101 
102  QMessageBox::critical(m_display, tr("Error"), QString(tr("All geometries selected must touch!")));
103  return;
104  }
105 
106  getBaseOID(*objSet, tr("Allow to merge geometries selecting the geom_id that will keep the attributes."));
107 
108  if (m_chosenOid == "")
109  return;
110 
112  if (!env.isValid())
113  {
114  QMessageBox::warning(m_display, tr("Merge Geometries"), tr("Invalid bounding box."));
115  return;
116  }
117 
119  if (m_feature == nullptr)
120  {
121  QMessageBox::information(m_display, tr("Merge Geometries"), tr("Pick Feature Failed."));
122  return;
123  }
124 
125  geom = dynamic_cast<te::gm::Geometry*>(m_gc->getGeometryN(0)->clone());
126  for (std::size_t i = 1; i < m_gc->getNumGeometries(); ++i)
128 
129  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator it;
130  for (it = m_oidSet->begin(); it != m_oidSet->end(); ++it)
131  {
132  if ((*it)->getValueAsString() == m_chosenOid)
133  {
134  m_feature->setId((*it)->clone());
135  break;
136  }
137  }
138 
139  m_feature->setGeometry(dynamic_cast<te::gm::Geometry*>(geom->clone()));
140 
141  delete geom;
142 
143  draw();
144 
145  storeFeature();
146 
147  emit geometriesEdited();
148  }
149  catch (std::exception& e)
150  {
151  QMessageBox::critical(m_display, tr("Merge Geometries"), QString(tr("Could not merge.") + " %1.").arg(e.what()));
152  return;
153  }
154 }
155 
157 {
158  bool result = false;
159  std::size_t j = 0;
160 
161  for (std::size_t i = 0; i < gc.getNumGeometries(); ++i)
162  {
163  std::size_t aux = 0;
164 
165  te::gm::Geometry* g1 = gc.getGeometryN(i);
166 
167  for (j = 0; j < gc.getNumGeometries(); j++)
168  {
169  if (j != i)
170  {
171  if (g1->disjoint(gc.getGeometryN(j)))
172  aux++;
173  }
174  }
175 
176  if (aux == (j-1))
177  {
178  result = true;
179  break;
180  }
181 
182  }
183 
184  return result;
185 }
186 
188 {
189  bool ok;
190  QStringList qValues;
191 
192  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator it;
193 
194  for (it = objSet.begin(); it != objSet.end(); ++it)
195  qValues.append((*it)->getValueAsString().c_str());
196 
197  QString qValue = QInputDialog::getItem(m_display, QString(tr("Merge Geometries")), QObject::tr(msg.toUtf8().data()), qValues, 0, false, &ok);
198 
199  if (qValue.isEmpty() || !ok)
200  return;
201 
202  for (it = objSet.begin(); it != objSet.end(); ++it)
203  {
204  if ((*it)->getValueAsString() == qValue.toUtf8().data())
205  m_chosenOid = (*it)->clone()->getValueAsString();
206 
207  m_oidSet->add((*it)->clone());
208  }
209 }
210 
212 {
213  std::size_t pType = 0;
214  std::string convOid;
215  std::vector<std::string> oidPropertyNames;
216  te::gm::Envelope env;
217 
218  std::unique_ptr<te::da::DataSet> ds(m_layer->getData(m_layer->getSelected()));
219 
220  std::unique_ptr<te::da::DataSetType> dt(m_layer->getSchema());
221 
223 
224  te::da::GetOIDPropertyNames(m_layer->getSchema().get(), oidPropertyNames);
225 
226  pType = ds->getPropertyDataType(te::da::GetPropertyPos(ds.get(), oidPropertyNames[0]));
227 
228  ds->moveBeforeFirst();
229  while (ds->moveNext())
230  {
231  switch (pType)
232  {
233  case te::dt::INT16_TYPE:
234  convOid = boost::lexical_cast<std::string>(ds->getInt16(oidPropertyNames[0]));
235  break;
236 
237  case te::dt::INT32_TYPE:
238  convOid = boost::lexical_cast<std::string>(ds->getInt32(oidPropertyNames[0]));
239  break;
240 
241  case te::dt::INT64_TYPE:
242  convOid = boost::lexical_cast<std::string>(ds->getInt64(oidPropertyNames[0]));
243  break;
244 
245  case te::dt::FLOAT_TYPE:
246  convOid = boost::lexical_cast<std::string>(ds->getFloat(oidPropertyNames[0]));
247  break;
248 
249  case te::dt::DOUBLE_TYPE:
250  convOid = boost::lexical_cast<std::string>(ds->getDouble(oidPropertyNames[0]));
251  break;
252 
254  convOid = boost::lexical_cast<std::string>(ds->getNumeric(oidPropertyNames[0]));
255  break;
256 
257  case te::dt::STRING_TYPE:
258  convOid = ds->getString(oidPropertyNames[0]);
259  break;
260  }
261  if (m_chosenOid == convOid)
262  {
263  env = *((ds->getGeometry(geomProp->getName()))->getMBR());
264 
267 
268  break;
269  }
270  }
271 
272  return env;
273 }
274 
276 {
277  const te::gm::Envelope& env = m_display->getExtent();
278  if (!env.isValid())
279  return;
280 
281  // Clear!
282  QPixmap* draft = m_display->getDraftPixmap();
283  draft->fill(Qt::transparent);
284 
285  // Initialize the renderer
286  Renderer& renderer = Renderer::getInstance();
287  renderer.begin(draft, env, m_display->getSRID());
288 
289  // Draw the layer edited geometries
290  renderer.drawRepository(m_layer->getId(), env, m_display->getSRID());
291 
292  // Draw the current geometry and the vertexes
293  renderer.draw(m_feature->getGeometry(), true);
294 
295  renderer.end();
296 
297  m_display->repaint();
298 }
299 
301 {
302  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator it;
303 
304  for (it = m_oidSet->begin(); it != m_oidSet->end(); ++it)
305  {
306  if ((*it)->getValueAsString() == m_chosenOid)
307  m_feature->setId((*it)->clone());
308  else
309  {
310  Feature* f = new Feature((*it)->clone(), new te::gm::Point(0, 0));
312 
313  RepositoryManager::getInstance().addFeature(m_layer->getId(), f->clone());
314 
315  delete f;
316  f = nullptr;
317  }
318  }
319 
321 }
322 
324 {
325  delete m_feature;
326 
327  te::gm::Envelope env = buildEnvelope(pos);
328 
329  try
330  {
331  m_feature = PickFeature(layer, env, m_display->getSRID());
332  if (m_feature)
334  }
335  catch (std::exception& e)
336  {
337  QMessageBox::critical(m_display, tr("Error"), QString(tr("The geometry cannot be selected from the layer. Details:") + " %1.").arg(e.what()));
338  }
339 }
340 
342 {
343  QPointF pixelOffset(4.0, 4.0);
344 
345  QRectF rect(pos - pixelOffset, pos + pixelOffset);
346 
347  // Converts rect boundary to world coordinates
348  QPointF ll(rect.left(), rect.bottom());
349  QPointF ur(rect.right(), rect.top());
350  ll = m_display->transform(ll);
351  ur = m_display->transform(ur);
352 
353  te::gm::Envelope env(ll.x(), ll.y(), ur.x(), ur.y());
354 
355  return env;
356 }
std::size_t getNumGeometries() const
It returns the number of geometries in this GeometryCollection.
virtual const std::string & getId() const
It returns the layer id.
void setId(te::da::ObjectId *id)
Definition: Feature.cpp:87
Geometric property.
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
MergeGeometriesTool(te::qt::widgets::MapDisplay *display, const te::map::AbstractLayerPtr &layer, const QCursor &cursor, QObject *parent=0)
TEDATAACCESSEXPORT std::size_t GetPropertyPos(const DataSet *dataset, const std::string &name)
Feature * clone() const
Definition: Feature.cpp:182
virtual bool disjoint(const Geometry *const rhs) const _NOEXCEPT_OP(false)
It returns true if the geometry object is spatially disjoint from rhs geometry.
te::gm::Geometry * getGeometry() const
Definition: Feature.cpp:139
void getBaseOID(const te::da::ObjectIdSet &objSet, QString msg)
A widget to control the display of a set of layers.
static te::dt::Date ds(2010, 01, 01)
void removeGeometryN(std::size_t i)
It removes the n-th geometry in this geometry collection.
virtual Geometry * Union(const Geometry *const rhs) const _NOEXCEPT_OP(false)
It returns a geometric object that represents the point set union with another geometry.
te::gm::GeometryCollection * m_gc
te::gm::GeometryCollection * gc
virtual QPointF transform(const QPointF &p)
Transforms the given point, in screen coordinates, to a point in world coordinates.
void setOperationTypeId(const te::edit::OperationType &currentOperationType)
Definition: Feature.cpp:124
static RepositoryManager & getInstance()
It returns a reference to the singleton instance.
A point with x and y coordinate values.
Definition: Point.h:50
An Envelope defines a 2D rectangular region.
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.
te::da::ObjectIdSet * m_oidSet
virtual std::unique_ptr< LayerSchema > getSchema() const =0
It returns the layer schema.
URI C++ Library.
Definition: Attributes.h:37
TEEDITEXPORT Feature * PickFeature(const te::map::AbstractLayerPtr &layer, const te::gm::Envelope &env, int srid)
static te::dt::TimeDuration dt(20, 30, 50, 11)
virtual const te::gm::Envelope & getExtent() const
It returns the world extent showned by the MapDisplay.
void draw(te::gm::Geometry *geom, bool showVertexes=false)
Definition: Renderer.cpp:260
virtual AbstractData * clone() const =0
It returns a clone of this object.
This class implements a concrete tool to merge polygons.
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
This is a singleton for rendering geometries and features.
Definition: Renderer.h:70
te::map::AbstractLayer * m_layer
Geometry * getGeometryN(std::size_t i) const
It returns the n-th geometry in this GeometryCollection.
void pickFeature(const te::map::AbstractLayerPtr &layer, const QPointF &pos)
virtual const te::da::ObjectIdSet * getSelected() const
It returns the selected group of this Layer.
virtual std::unique_ptr< te::da::DataSet > getData(te::common::TraverseType travType=te::common::FORWARDONLY, const te::common::AccessPolicy accessPolicy=te::common::RAccess) const =0
It gets the dataset identified by the layer name.
virtual QPixmap * getDraftPixmap() const
It returns the map display draft pixmap.
std::set< ObjectId *, te::common::LessCmp< ObjectId * > >::const_iterator end() const
Returns an iterator for the object ids in container.
te::gm::Envelope buildEnvelope(const QPointF &pos)
void add(Geometry *g)
It adds the geometry into the collection.
void begin(QPaintDevice *device, const te::gm::Envelope &e, int srid)
Definition: Renderer.cpp:59
bool spatialRelationDisjoint(te::gm::GeometryCollection &gc)
void drawRepository(const std::string &source, const te::gm::Envelope &e, int srid)
Definition: Renderer.cpp:78
void setCursor(const QCursor &cursor)
It sets the tool cursor.
MapDisplay * m_display
The map display associated with the tool.
Definition: AbstractTool.h:171
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
virtual int getSRID() const
It returns the Spatial Reference System ID associated to the Layer.
void setGeometry(te::gm::Geometry *geom)
Definition: Feature.cpp:95
It is a collection of other geometric objects.
TEDATAACCESSEXPORT te::gm::GeometryProperty * GetFirstGeomProperty(const DataSetType *dt)
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
void transform(int oldsrid, int newsrid)
It will transform the coordinates of the Envelope from the old SRS to the new one.
std::set< ObjectId *, te::common::LessCmp< ObjectId * > >::const_iterator begin() const
Returns an iterator for the object ids in container.
TEGEOMEXPORT te::gm::Geometry * Validate(te::gm::Geometry *geom)
Get/create a valid version of the geometry given. If the geometry is a polygon or multi polygon...
bool isValid() const
It tells if the rectangle is valid or not.