MultiThreadMapDisplay.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/qt/widgets/canvas/MultiThreadMapDisplay.cpp
22 
23  \brief A multi thread Qt4 widget to control the display of a set of layers.
24 */
25 
26 // TerraLib
27 #include "../../../common/STLUtils.h"
28 #include "../../../maptools/Utils.h"
29 #include "../../../maptools/AbstractLayer.h"
30 #include "../../../se/Style.h"
31 #include "MultiThreadMapDisplay.h"
32 #include "Canvas.h"
33 #include "DrawThread.h"
34 #include "ScaleWidget.h"
35 #include "Grid.h"
36 #include "ThreadManager.h"
37 
38 // Qt
39 #include <QApplication>
40 #include <QImage>
41 #include <QPainter>
42 
43 void RemoveImage(const std::string lId, std::map<std::string, QImage*>& imgs)
44 {
45  std::map<std::string, QImage*>::iterator it = imgs.find(lId);
46 
47  if(it != imgs.end())
48  {
49  delete it->second;
50  imgs.erase(lId);
51  }
52 }
53 
54 void RemoveImage(te::map::AbstractLayer* layer, std::map<std::string, QImage*>& imgs)
55 {
56  std::string lId = layer->getId();
57  RemoveImage(lId, imgs);
58 }
59 
60 te::qt::widgets::MultiThreadMapDisplay::MultiThreadMapDisplay(const QSize& size, const bool& showFeedback, QWidget* parent, Qt::WindowFlags f)
61  : te::qt::widgets::MapDisplay(size, parent, f),
62  m_showFeedback(showFeedback),
63  m_synchronous(false),
64  m_tmger(nullptr)
65 {
66  setAttribute(Qt::WA_OpaquePaintEvent, true);
67 }
68 
70 : te::qt::widgets::MapDisplay(parent, f),
71 m_showFeedback(showFeedback),
72 m_synchronous(false),
73 m_tmger(nullptr)
74 {
75  setAttribute(Qt::WA_OpaquePaintEvent, true);
76 }
77 
79 {
80  if (m_isDrawing)
82 
84  m_images.clear();
85 }
86 
87 void te::qt::widgets::MultiThreadMapDisplay::setLayerList(const std::list<te::map::AbstractLayerPtr>& layers)
88 {
89  m_layerList = layers;
90 
91  m_visibleLayers.clear();
92 }
93 
95 {
96  if(m_isDrawing)
97  return;
98 
99  m_extent = e;
100 
101  updateTransform();
102 
103  e = m_extent;
104 
105  //Visualization scale limit control
106  if (m_minScale != 0.0 || m_maxScale != 0.0)
107  {
108  double scale = std::round(getScale());
109 
110  if (scale < m_minScale)
111  {
113  }
114  else if (scale > m_maxScale)
115  {
117  }
118  }
119 
120  if(doRefresh)
121  refresh(doRefresh);
122 
123  if (m_graphicScale != nullptr)
125 
126  emit extentChanged();
127 }
128 
130 {
131  m_cancel = false;
132 
133  if(m_isDrawing)
134  return;
135 
136  m_draftPixmap->fill(Qt::transparent);
137 
138  // Considering only the visible layers
139  m_visibleLayers.clear();
140 
142 
143  if(m_visibleLayers.empty())
144  {
146  m_images.clear();
147 
149 
150  repaint();
151 
152  m_isDrawing = false;
153 
154  return;
155  }
156 
157  m_isDrawing = true;
158 
159  if(redraw)
160  {
162  m_images.clear();
163  }
164 
165  std::map<std::string, QImage*> imgs;
166 
167  double scale = getScale();
168 
169  for(std::list<te::map::AbstractLayerPtr>::iterator it = m_visibleLayers.begin(); it != m_visibleLayers.end(); ++it)
170  {
171  std::string lId = (*it)->getId();
172 
173  std::map<std::string, QImage*>::iterator imgIt = m_images.find(lId);
174 
175  if(imgIt != m_images.end())
176  {
177  imgs[lId] = imgIt->second;
178  m_images.erase(lId);
179  }
180  else
181  {
182  QImage* img = new QImage(size(), QImage::Format_ARGB32_Premultiplied);
183  imgs[lId] = img;
184 
185  DrawThread* thread = new DrawThread(imgs[lId], (*it).get(), &m_extent, m_backgroundColor, m_srid, scale, m_hAlign, m_vAlign);
186  m_threads.push_back(thread);
187  }
188  }
189 
190  if(!m_images.empty())
191  {
193  m_images.clear();
194  }
195 
196  m_images = imgs;
197 
198  if(m_tmger != nullptr)
199  delete m_tmger;
200 
201  m_tmger = nullptr;
202 
203  if(!m_threads.empty())
204  {
205  QApplication::setOverrideCursor(Qt::WaitCursor);
206 
207  int interval = (m_showFeedback) ? 1000 : -1;
208 
209  m_tmger = new ThreadManager(m_threads, interval);
210 
211  connect(m_tmger, SIGNAL(showFeedback()), SLOT(showFeedback()));
212 
213  connect(m_tmger, SIGNAL(finished()), SLOT(onRenderingFinished()));
214 
215  m_tmger->run();
216  }
217  else
219 }
220 
222 {
223  if(!m_extent.isValid())
224  return QPointF();
225 
226  return m_matrix.inverted().map(p);
227 }
228 
230 {
231  m_synchronous = on;
232 }
233 
235 {
236  if (m_isDrawing)
237  onDrawCanceled();
238 
239  RemoveImage(layer.get(), m_images);
240 
241  if(redraw)
242  refresh();
243 }
244 
245 void te::qt::widgets::MultiThreadMapDisplay::updateLayer(std::vector<te::map::AbstractLayerPtr> layers, bool redraw)
246 {
247  if (m_isDrawing)
248  onDrawCanceled();
249 
250  for (std::size_t i = 0; i < layers.size(); ++i)
251  {
252  RemoveImage(layers[i].get(), m_images);
253  }
254 
255  if (redraw)
256  refresh();
257 }
258 
260 {
261  if (m_isDrawing)
262  onDrawCanceled();
263 
264  if(!m_images.empty())
265  {
267  m_images.clear();
268  }
269 
271 }
272 
273 
275 {
276  if(!m_extent.isValid())
277  return;
278 
279  // Compute aspect ratio
280  double ww = m_extent.m_urx - m_extent.m_llx;
281  double wh = m_extent.m_ury - m_extent.m_lly;
282 
283  double widthByHeight = static_cast<double>(width()) / static_cast<double>(height());
284 
285  if(widthByHeight > ww / wh)
286  {
287  double v = ww;
288  ww = wh * widthByHeight;
289  m_extent.m_llx = m_extent.m_llx - (ww - v) * 0.5;
290  m_extent.m_urx = m_extent.m_llx + ww;
291  }
292  else
293  {
294  double v = wh;
295  wh = ww / widthByHeight;
296  m_extent.m_lly = m_extent.m_lly - (wh - v) * 0.5;
297  m_extent.m_ury = m_extent.m_lly + wh;
298  }
299 
300  // Bulding the transform matrix
301  double xScale = static_cast<double>(width()) / (m_extent.m_urx - m_extent.m_llx);
302  double yScale = static_cast<double>(height()) / (m_extent.m_ury - m_extent.m_lly);
303  m_matrix.reset();
304  m_matrix.scale(xScale, -yScale);
305  m_matrix.translate(-m_extent.m_llx, -m_extent.m_ury);
306 }
307 
309 {
311 
312  QPainter painter(m_displayPixmap);
313 
314  for(std::list<te::map::AbstractLayerPtr>::reverse_iterator it = m_visibleLayers.rbegin(); it != m_visibleLayers.rend(); ++it)
315  {
316  te::map::AbstractLayer* l = (*it).get();
317 
318  std::map<std::string, QImage*>::iterator img_it = m_images.find(l->getId());
319 
320  if(img_it == m_images.end())
321  continue;
322 
323  painter.setCompositionMode((QPainter::CompositionMode)l->getCompositionMode());
324 
325  painter.drawImage(0, 0, *img_it->second);
326  }
327 
328  repaint(); // or update()? Which is the best here?!
329 }
330 
332  const int& /*index*/, const QImage& /*image*/)
333 {
334 }
335 
337 {
338  showFeedback();
339 
340  m_isDrawing = false;
341 
342  QMap<QString, QString> errors;
343 
344  for(std::vector<QRunnable*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
345  {
346  DrawThread* th = static_cast<DrawThread*>(*it);
347 
348  if(!th->hasFinished())
349  {
350  QString lId = th->layerId();
351  QString errorm = th->errorMessage();
352 
353  if(!errorm.isEmpty())
354  errors[lId] = errorm;
355 
356  RemoveImage(lId.toUtf8().data(), m_images);
357  }
358  }
359 
360  if(!m_threads.empty())
361  {
363  m_threads.clear();
364  }
365 
366  QApplication::restoreOverrideCursor();
367 
368  emit drawLayersFinished(errors);
369 }
370 
372 {
373  m_cancel = true;
374  if (m_tmger != nullptr)
376 }
377 
virtual const std::string & getId() const
It returns the layer id.
void onDrawLayerFinished(const int &index, const QImage &image)
A canvas built on top of Qt.
QString layerId() const
Definition: DrawThread.cpp:106
This is the base class for layers.
Definition: AbstractLayer.h:77
virtual QPointF transform(const QPointF &p)
Transforms the given point, in screen coordinates, to a point in world coordinates.
te::map::AlignType m_hAlign
The display horizontal align.
Thread to draw a Layer in a PaintDevice.
void refresh(bool redraw=false)
It updates the contents in the map display.
bool m_isDrawing
A flag that indicates if the map display is drawing.
double m_urx
Upper right corner x-coordinate.
virtual double getScale() const
Calculates and return the current scale.
QString errorMessage() const
Definition: DrawThread.cpp:101
void setExtent(te::gm::Envelope &e, bool doRefresh=true)
It sets the world visible area and refreshes the contents in the map display.
te::map::AlignType m_vAlign
The display vertical align.
A widget to control the display of a set of layers.
QPixmap * m_displayPixmap
This pixmap will be the result of all canvas pixmap drawing, i. e., the result of drawing all visible...
void resizeEvent(QResizeEvent *e)
This event handler receives widget resize events wich are passed in the event parameter.
void drawLayersFinished(const QMap< QString, QString > &errors)
This signal is emitted when the draw process ends. i.e. when all layers have been drawn...
A multi thread Qt4 widget to control the display of a set of layers.
bool m_showFeedback
A flag that indicates if the map display will show drawing feedback.
Manager for threads of rendering.
te::map::CompositionMode getCompositionMode() const
It returns the composition mode.
CompositionMode
The composition mode used to render the canvas.
bool m_synchronous
A flag that indicates if the map display is synchronous or asynchronous.
void updateLayer(te::map::AbstractLayerPtr layer, bool redraw=true)
void setLayerList(const std::list< te::map::AbstractLayerPtr > &layers)
double m_llx
Lower left corner x-coordinate.
QMatrix m_matrix
Used to convert screen coordinates to world coordinates.
An Envelope defines a 2D rectangular region.
URI C++ Library.
Definition: Attributes.h:37
te::gm::Polygon * p
int m_srid
The display SRS.
te::gm::Envelope m_extent
The display extent.
ScaleWidget * m_graphicScale
Graphic scale pointer.
double m_lly
Lower left corner y-coordinate.
std::vector< QRunnable * > m_threads
The set of threads used to draw the layer list.
std::list< te::map::AbstractLayerPtr > m_layerList
The layer list to be displayed.
double m_ury
Upper right corner y-coordinate.
Contains an implementation of a grid.
virtual void resizeEvent(QResizeEvent *e)
This event handler receives widget resize events wich are passed in the event parameter.
MultiThreadMapDisplay(const QSize &size, const bool &showFeedback=true, QWidget *parent=0, Qt::WindowFlags f=0)
It constructs an empty multi thread map display with the given dimensions which is a child of parent...
QPixmap * m_draftPixmap
The draft pixmap can be used to draw some feedback on map display.
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
void FreeContents(boost::unordered_map< K, V * > &m)
This function can be applied to a map of pointers. It will delete each pointer in the map...
Definition: BoostUtils.h:55
QColor m_backgroundColor
Background color.
void RemoveImage(const std::string lId, std::map< std::string, QImage * > &imgs)
bool isValid() const
It tells if the rectangle is valid or not.
virtual bool setScale(const double &scale)
Defines the scale and calculates envelope based on the requested scale.
std::list< te::map::AbstractLayerPtr > m_visibleLayers
The set of visible layers.
Contains an implementation of a graphic scale.
void updateScaleFactor()
Updates the scale values.
std::map< std::string, QImage * > m_images
The set of images built by each thread. It will be used to compose the final result, keeping the layer list order.
TEMAPEXPORT void GetVisibleLayers(const std::list< te::map::AbstractLayerPtr > &layers, std::list< te::map::AbstractLayerPtr > &visibleLayers)
It gets the visible layers of the given layer list.