VertexTool.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/edit/qt/tools/VertexTool.cpp
22 
23  \brief This class implements a concrete tool for vertex operations (move, add, etc.).
24 */
25 
26 // TerraLib
27 #include "../../../common/STLUtils.h"
28 #include "../../../dataaccess/dataset/ObjectId.h"
29 #include "../../../geometry/Coord2D.h"
30 #include "../../../geometry/Geometry.h"
31 #include "../../../geometry/LineString.h"
32 #include "../../../geometry/MultiPolygon.h"
33 #include "../../../geometry/Polygon.h"
34 #include "../../../geometry/Utils.h"
35 #include "../../../qt/widgets/canvas/MapDisplay.h"
36 #include "../../../qt/widgets/Utils.h"
37 #include "../../Feature.h"
38 #include "../../RepositoryManager.h"
39 #include "../../Utils.h"
40 #include "../Renderer.h"
41 #include "../Utils.h"
42 #include "VertexTool.h"
43 
44 // Qt
45 #include <QMessageBox>
46 #include <QMouseEvent>
47 #include <QPainter>
48 #include <QPixmap>
49 
50 // STL
51 #include <cassert>
52 #include <memory>
53 #include <string>
54 
56  : GeometriesUpdateTool(display, layer.get(), parent),
57  m_currentStage(FEATURE_SELECTION),
58  m_isEdited(false),
59  m_fixGeometry(fixGeometry),
60  m_stack(UndoStackManager::getInstance())
61 {
63 
64  updateCursor();
65 
66  draw();
67 }
68 
70 
72 {
73  if (e->button() != Qt::LeftButton)
74  return false;
75 
76  Qt::KeyboardModifiers keys = e->modifiers();
77 
78  if(e->button() == Qt::LeftButton && m_currentStage == VERTEX_FOUND)
79  {
80  // Moving...
81  if(keys == Qt::NoModifier)
82  {
84 
85  m_isEdited = true;
86 
87  return true;
88  }
89 
90  // Removing...
91  if(keys == Qt::ShiftModifier)
92  {
94 
96 
98 
99  m_isEdited = true;
100 
101  updateRTree();
102 
103  draw();
104 
105  return true;
106  }
107 
108  }
109 
110  // This operation will be handled by mouse double click
111  if(m_currentStage == VERTEX_READY_TO_ADD)
112  return false;
113 
114  // Else...
116 
117  return false;
118 }
119 
121 {
122  switch(m_currentStage)
123  {
124  case VERTEX_SEARCH:
125  case VERTEX_FOUND:
126  case VERTEX_READY_TO_ADD:
127  {
128  if(m_rtree.isEmpty())
129  return false;
130 
132 
133  // Search on rtree
134  std::vector<VertexIndex> report;
135  m_rtree.search(env, report);
136 
137  if(!report.empty()) // Vertex found!
138  {
140 
141  m_currentVertexIndex = report[0];
142 
143  draw();
144 
145  return false;
146  }
147 
148  // Else, try search "virtual vertex" at a segment
150 
151  std::unique_ptr<te::gm::Point> borderPoint;
152 
153  if(m_feature != nullptr)
154  {
155  std::unique_ptr<te::gm::Geometry> geometryFromEnvelope(te::gm::GetGeomFromEnvelope(&env, m_display->getSRID()));
156 
157  if(m_feature->getGeometry()->intersects(geometryFromEnvelope.get()) && !m_feature->getGeometry()->contains(geometryFromEnvelope.get())) // Mouse over a segment?
158  borderPoint.reset(new te::gm::Point(env.getCenter().x, env.getCenter().y));
159  }
160 
161  borderPoint.get() != nullptr ? setStage(VERTEX_READY_TO_ADD) : setStage(VERTEX_SEARCH);
162 
163  draw(borderPoint.get());
164 
165  return false;
166  }
167 
168  case VERTEX_MOVING:
169  {
170  QPointF point = GetPosition(e);
171  point = m_display->transform(point);
172 
173  MoveVertex(m_lines, m_currentVertexIndex, point.x(), point.y());
174 
175  draw();
176 
177  return false;
178  }
179 
180  default:
181  return false;
182  }
183 
184  return false;
185 }
186 
188 {
190  {
191  if (e->button() != Qt::LeftButton)
192  return false;
193 
195 
196  if (m_feature)
198  }
199  else if (m_currentStage == VERTEX_MOVING)
200  {
201  updateRTree();
202 
204  }
205 
206  if (m_fixGeometry && m_feature)
207  {
208  if (!m_feature->getGeometry()->isValid())
209  {
211 
212  m_lines.clear();
214 
215  updateRTree();
216  }
217  }
218 
219  storeFeature();
220 
222 
223  return false;
224 }
225 
227 {
228  if(e->button() == Qt::LeftButton && m_currentStage == VERTEX_READY_TO_ADD)
229  {
230  // Added point
231  QPointF point = GetPosition(e);
232 
233  // Added point extent
234  te::gm::Envelope e = buildEnvelope(point);
235 
236  // Convert to world coordinates
237  point = m_display->transform(point);
238 
239  AddVertex(m_lines, point.x(), point.y(), e, m_display->getSRID());
240 
242 
244 
245  m_isEdited = true;
246 
247  updateRTree();
248 
249  draw();
250 
251  return true;
252  }
253 
254  return false;
255 }
256 
258 {
259  delete m_feature;
260 
262 
263  m_lines.clear();
264 
266 
267  m_rtree.clear();
268 
269  m_isEdited = false;
270 }
271 
272 void te::edit::VertexTool::pickFeature(const te::map::AbstractLayerPtr& layer, const QPointF& pos)
273 {
274  te::gm::Envelope env = buildEnvelope(pos);
275  pickFeature(layer, env);
276 }
277 
279 {
280  reset();
281 
282  try
283  {
284  m_feature = PickFeature(layer, env, m_display->getSRID());
285 
286  if (m_feature == nullptr)
287  return;
288 
291 
292  m_lines.clear();
293 
294  if(m_feature != nullptr)
296 
297  updateRTree();
298 
299  draw();
300  }
301  catch(std::exception& e)
302  {
303  QMessageBox::critical(m_display, tr("Error"), QString(tr("The geometry cannot be selected from the layer. Details:") + " %1.").arg(e.what()));
304  }
305 }
306 
308 {
309  const te::gm::Envelope& env = m_display->getExtent();
310  if(!env.isValid())
311  return;
312 
313  // Clear!
314  QPixmap* draft = m_display->getDraftPixmap();
315  draft->fill(Qt::transparent);
316 
317  // Initialize the renderer
318  Renderer& renderer = Renderer::getInstance();
319  renderer.begin(draft, env, m_display->getSRID());
320 
321  // Draw the layer edited geometries
322  renderer.drawRepository(m_layer->getId(), env, m_display->getSRID());
323 
324  if(m_lines.empty())
325  {
326  renderer.end();
327  m_display->repaint();
328  return;
329  }
330 
331  // Draw the vertexes
332  if (m_feature != nullptr)
333  {
334  if (RepositoryManager::getInstance().hasIdentify(m_layer->getId(), m_feature->getId()) == false)
335  renderer.draw(m_feature->getGeometry(), true);
336  else
337  renderer.drawVertexes(m_feature->getGeometry());
338  }
339 
340  // Draw the current vertex
342  {
344  std::unique_ptr<te::gm::Point> point(line->getPointN(m_currentVertexIndex.m_pos));
345 
346  renderer.setPointStyle("circle", Qt::transparent, Qt::blue, 3, 24);
347  renderer.draw(point.get());
348  }
349 
350  // Draw the virtual vertex
351  if(virtualVertex)
352  {
353  assert(virtualVertex);
354 
355  renderer.setPointStyle("circle", Qt::transparent, Qt::darkGreen, 3, 24);
356  renderer.draw(virtualVertex);
357  }
358 
359  renderer.end();
360 
361  m_display->repaint();
362 
363 }
364 
366 {
367  draw();
368 }
369 
371 {
372  QPointF pixelOffset(4.0, 4.0);
373 
374  QRectF rect(pos - pixelOffset, pos + pixelOffset);
375 
376  // Converts rect boundary to world coordinates
377  QPointF ll(rect.left(), rect.bottom());
378  QPointF ur(rect.right(), rect.top());
379  ll = m_display->transform(ll);
380  ur = m_display->transform(ur);
381 
382  te::gm::Envelope env(ll.x(), ll.y(), ur.x(), ur.y());
383 
384  return env;
385 }
386 
388 {
389  m_rtree.clear();
390 
391  for(std::size_t i = 0; i < m_lines.size(); ++i)
392  {
394 
395  for(std::size_t j = 0; j < line->getNPoints(); ++j)
396  {
397  te::gm::Envelope e(line->getX(j), line->getY(j), line->getX(j), line->getY(j));
398 
399  VertexIndex index;
400  index.setIndex(i, j);
401 
402  m_rtree.insert(e, index);
403  }
404  }
405 }
406 
408 {
409  m_currentStage = stage;
410  updateCursor();
411 }
412 
414 {
415  switch(m_currentStage)
416  {
417  case FEATURE_SELECTION:
418  case VERTEX_SEARCH:
419  setCursor(Qt::ArrowCursor);
420  break;
421 
422  case VERTEX_FOUND:
423  setCursor(Qt::OpenHandCursor);
424  break;
425 
426  case VERTEX_MOVING:
427  setCursor(Qt::ClosedHandCursor);
428  break;
429 
430  default:
431  setCursor(Qt::ArrowCursor);
432  }
433 }
434 
436 {
437  if (m_feature == nullptr)
438  return;
439 
441 
442  emit geometriesEdited();
443 }
444 
446 {
447  if (m_feature == nullptr)
448  return;
449 
450  if (!m_isEdited)
451  return;
452 
454 
455  QUndoCommand* command = new AddCommand(m_display, m_layer, m_feature->clone()->getId());
456  connect(dynamic_cast<AddCommand*>(command), SIGNAL(commandFeedback()), SLOT(onCommandFeedback()));
457 
458  m_stack.addUndoStack(command);
459 
460 }
461 
463 {
464  m_lines.clear();
465 
466  if (m_stack.m_currentIndex < 0)
467  {
468  m_feature = nullptr;
469  return;
470  }
471 
472  std::size_t pos = (m_stack.m_currentIndex < 0) ? 0 : m_stack.m_currentIndex;
473 
474  m_feature = m_stack.getAddWatches()[pos]->clone();
475 
477 
478  updateRTree();
479 }
480 
482 {
483  m_feature = nullptr;
484 
486 
487  m_lines.clear();
488 
490 
491  m_rtree.clear();
492 }
VertexTool(te::qt::widgets::MapDisplay *display, const te::map::AbstractLayerPtr &layer, bool fixGeometry=false, QObject *parent=0)
It constructs a vertex tool associated with the given map display.
Definition: VertexTool.cpp:55
virtual const std::string & getId() const
It returns the layer id.
Undo/Redo for add one components.
Definition: AddCommand.h:52
UndoStackManager & m_stack
Definition: VertexTool.h:157
TEEDITEXPORT void MoveVertex(std::vector< te::gm::LineString * > &lines, const VertexIndex &index, const double &x, const double &y)
double y
y-coordinate.
Definition: Coord2D.h:114
void setPointStyle(const QString &mark, const QColor &fillColor, const QColor &contourColor, const std::size_t &contourWidth, const std::size_t &size)
Definition: Renderer.cpp:361
StageType
Defines the operation stage to this tool.
Definition: VertexTool.h:85
double x
x-coordinate.
Definition: Coord2D.h:113
This class implements a concrete tool for vertex operations (move, add, etc.).
void setStage(StageType stage)
Definition: VertexTool.cpp:407
te::da::ObjectId * getId() const
Definition: Feature.cpp:134
Feature * clone() const
Definition: Feature.cpp:182
void addWatch(Feature *feature)
std::unique_ptr< Point > getPointN(std::size_t i) const
It returns the specified point in this LineString.
bool mouseReleaseEvent(QMouseEvent *e)
This event handler can be reimplemented in a concrete tool class to receive mouse release events for ...
Definition: VertexTool.cpp:187
~VertexTool()
Destructor.
const std::vector< Feature * > & getAddWatches() const
te::gm::Geometry * getGeometry() const
Definition: Feature.cpp:139
A widget to control the display of a set of layers.
virtual bool intersects(const Geometry *const rhs) const _NOEXCEPT_OP(false)
It returns true if the geometry object spatially intersects rhs geometry.
bool mousePressEvent(QMouseEvent *e)
This event handler can be reimplemented in a concrete tool class to receive mouse press events for th...
Definition: VertexTool.cpp:71
const double & getY(std::size_t i) const
It returns the n-th y coordinate value.
unsigned int line
std::vector< te::gm::LineString * > m_lines
Definition: VertexTool.h:151
Coord2D getCenter() const
It returns the rectangle&#39;s center coordinate.
void addUndoStack(QUndoCommand *command)
Method that insert command Undo/Redo of type AddCommand in the Undo/Redo stack.
int getSRID() const _NOEXCEPT_OP(true)
It returns the Spatial Reference System ID associated to this geometric object.
TEEDITEXPORT void RemoveVertex(std::vector< te::gm::LineString * > &lines, const VertexIndex &index)
virtual QPointF transform(const QPointF &p)
Transforms the given point, in screen coordinates, to a point in world coordinates.
LineString is a curve with linear interpolation between points.
Definition: LineString.h:62
static T & getInstance()
It returns a reference to the singleton instance.
Definition: Singleton.h:126
A point with x and y coordinate values.
Definition: Point.h:50
virtual bool isValid() const _NOEXCEPT_OP(false)
It tells if the geometry is well formed.
An Envelope defines a 2D rectangular region.
void setIndex(const std::size_t &line, const std::size_t &pos)
const double & getX(std::size_t i) const
It returns the n-th x coordinate value.
virtual int getSRID() const
It return the Spatial Reference System used by the Map Display.
te::gm::Envelope buildEnvelope(const QPointF &pos)
Definition: VertexTool.cpp:370
bool mouseMoveEvent(QMouseEvent *e)
This event handler can be reimplemented in a concrete tool class to receive mouse move events for the...
Definition: VertexTool.cpp:120
TEEDITEXPORT Feature * PickFeature(const te::map::AbstractLayerPtr &layer, const te::gm::Envelope &env, int srid)
TEEDITQTEXPORT QPointF GetPosition(QMouseEvent *e)
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
std::size_t getNPoints() const
It returns the number of points (vertexes) in the linestring.
Definition: LineString.h:193
virtual bool contains(const Geometry *const rhs) const _NOEXCEPT_OP(false)
It returns true if this geometry object spatially contains rhs geometry.
VertexIndex m_currentVertexIndex
Definition: VertexTool.h:152
te::sam::rtree::Index< VertexIndex, 8 > m_rtree
Definition: VertexTool.h:153
This is a singleton for rendering geometries and features.
Definition: Renderer.h:70
te::map::AbstractLayer * m_layer
void draw(te::gm::Point *virtualVertex=0)
Definition: VertexTool.cpp:307
TEEDITEXPORT void AddVertex(std::vector< te::gm::LineString * > &lines, const double &x, const double &y, const te::gm::Envelope &env, int srid)
virtual QPixmap * getDraftPixmap() const
It returns the map display draft pixmap.
StageType m_currentStage
Definition: VertexTool.h:154
void drawVertexes(te::gm::Geometry *geom)
Definition: Renderer.cpp:292
void begin(QPaintDevice *device, const te::gm::Envelope &e, int srid)
Definition: Renderer.cpp:59
TEEDITEXPORT void GetLines(te::gm::Geometry *geom, std::vector< te::gm::LineString * > &lines)
bool mouseDoubleClickEvent(QMouseEvent *e)
This event handler can be reimplemented in a concrete tool class to receive mouse double click events...
Definition: VertexTool.cpp:226
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
void setGeometry(te::gm::Geometry *geom)
Definition: Feature.cpp:95
virtual void transform(int srid) _NOEXCEPT_OP(false)=0
It converts the coordinate values of the geometry to the new spatial reference system.
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
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.
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
void pickFeature(const te::map::AbstractLayerPtr &layer, const QPointF &pos)
Definition: VertexTool.cpp:272