All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "DrawLayerThread.h"
30 #include "MultiThreadMapDisplay.h"
31 
32 // Qt
33 #include <QApplication>
34 #include <QCursor>
35 #include <QPainter>
36 
37 te::qt::widgets::MultiThreadMapDisplay::MultiThreadMapDisplay(const QSize& size, const bool& showFeedback, QWidget* parent, Qt::WindowFlags f)
38  : te::qt::widgets::MapDisplay(size, parent, f),
39  m_showFeedback(showFeedback),
40  m_synchronous(false)
41 {
42  setAttribute(Qt::WA_OpaquePaintEvent, true);
43 }
44 
45 te::qt::widgets::MultiThreadMapDisplay::MultiThreadMapDisplay(QWidget* parent, const bool& showFeedback, Qt::WindowFlags f)
46 : te::qt::widgets::MapDisplay(parent, f),
47 m_showFeedback(showFeedback),
48 m_synchronous(false)
49 {
50  setAttribute(Qt::WA_OpaquePaintEvent, true);
51 }
52 
54 {
55  te::common::FreeContents(m_threads);
56 }
57 
59 {
60  if(m_isDrawing)
61  return;
62 
64 
65  updateTransform();
66 
67  e = m_extent;
68 
69  if(doRefresh)
70  refresh();
71 
72  emit extentChanged();
73 }
74 
76 {
77  if(m_isDrawing)
78  return;
79 
80  // Cleaning...
81  m_displayPixmap->fill(m_backgroundColor);
82  m_draftPixmap->fill(Qt::transparent);
83 
84  // Considering only the visible layers
85  m_visibleLayers.clear();
86  te::map::GetVisibleLayers(m_layerList, m_visibleLayers);
87 
88  if(m_visibleLayers.empty())
89  {
90  repaint();
91  return;
92  }
93 
94  int n = m_visibleLayers.size() - m_threads.size();
95  for(int i = 0; i < n; ++i)
96  {
97  DrawLayerThread* thread = new DrawLayerThread;
98 
99  if(m_showFeedback) // Do you want show feedbacks?
100  connect(thread, SIGNAL(feedback(QImage)), this, SLOT(showFeedback(QImage)));
101 
102  connect(thread, SIGNAL(drawLayerFinished(int, QImage)), this, SLOT(onDrawLayerFinished(int, QImage)));
103 
104  m_threads.push_back(thread);
105  }
106 
107  QApplication::setOverrideCursor(Qt::WaitCursor);
108 
109  m_isDrawing = true;
110 
111  std::size_t i = 0;
112  std::list<te::map::AbstractLayerPtr>::reverse_iterator it;
113  for(it = m_visibleLayers.rbegin(); it != m_visibleLayers.rend(); ++it) // for each layer
114  {
115  m_threads[i]->draw(it->get(), m_extent, m_srid, size(), i);
116  i++;
117  }
118 
119  if(m_synchronous)
120  {
121  QEventLoop wait;
122  connect(this, SIGNAL(drawLayersFinished(const QMap<QString, QString>&)), &wait, SLOT(quit()));
123  wait.exec();
124  }
125 }
126 
128 {
129  if(!m_extent.isValid())
130  return QPointF();
131 
132  return m_matrix.inverted().map(p);
133 }
134 
136 {
137  m_synchronous = on;
138 }
139 
141 {
142  if(!m_extent.isValid())
143  return;
144 
145  // Compute aspect ratio
146  double ww = m_extent.m_urx - m_extent.m_llx;
147  double wh = m_extent.m_ury - m_extent.m_lly;
148 
149  double widthByHeight = static_cast<double>(width()) / static_cast<double>(height());
150 
151  if(widthByHeight > ww / wh)
152  {
153  double v = ww;
154  ww = wh * widthByHeight;
155  m_extent.m_llx = m_extent.m_llx - (ww - v) * 0.5;
156  m_extent.m_urx = m_extent.m_llx + ww;
157  }
158  else
159  {
160  double v = wh;
161  wh = ww / widthByHeight;
162  m_extent.m_lly = m_extent.m_lly - (wh - v) * 0.5;
163  m_extent.m_ury = m_extent.m_lly + wh;
164  }
165 
166  // Bulding the transform matrix
167  double xScale = static_cast<double>(width()) / (m_extent.m_urx - m_extent.m_llx);
168  double yScale = static_cast<double>(height()) / (m_extent.m_ury - m_extent.m_lly);
169  m_matrix.reset();
170  m_matrix.scale(xScale, -yScale);
171  m_matrix.translate(-m_extent.m_llx, -m_extent.m_ury);
172 }
173 
175 {
176  QPainter painter(m_displayPixmap);
177  painter.setOpacity(0.1); // To improve user visual experience!
178  painter.drawImage(0, 0, image);
179  //painter.drawPixmap(0, 0, QPixmap::fromImage(image));
180  repaint(); // or update()? Which is the best here?!
181 }
182 
183 void te::qt::widgets::MultiThreadMapDisplay::onDrawLayerFinished(const int& index, const QImage& image)
184 {
185  m_images.insert(std::pair<int, QImage>(index, image));
186  if(m_images.size() != m_visibleLayers.size())
187  {
188  QPainter painter(m_displayPixmap);
189  painter.drawImage(0, 0, image);
190  //painter.drawPixmap(0, 0, QPixmap::fromImage(image));
191  painter.end();
192 
193  repaint();
194 
195  return;
196  }
197 
198  m_displayPixmap->fill(m_backgroundColor);
199 
200  QPainter painter(m_displayPixmap);
201 
202  std::list<te::map::AbstractLayerPtr>::reverse_iterator itLayer = m_visibleLayers.rbegin();
203  std::map<int, QImage>::iterator it;
204  for(it = m_images.begin(); it != m_images.end(); ++it)
205  {
206  painter.setCompositionMode((QPainter::CompositionMode)itLayer->get()->getCompositionMode());
207 
208  painter.drawImage(0, 0, it->second);
209  //painter.drawPixmap(0, 0, QPixmap::fromImage(it->second));
210 
211  ++itLayer;
212  }
213 
214  painter.end();
215 
216  m_images.clear();
217 
218  repaint(); // or update()? Which is the best here?!
219 
220  m_isDrawing = false;
221 
222  QApplication::restoreOverrideCursor();
223 
224  // Building the error messages
225  QMap<QString, QString> errors;
226  for(std::size_t i = 0; i < m_threads.size(); ++i)
227  {
228  DrawLayerThread* t = m_threads[i];
229  if(t->finishedWithSuccess())
230  continue;
231  errors.insert(t->getLayer()->getId().c_str(), t->getErrorMessage());
232  }
233 
234  emit drawLayersFinished(errors);
235 }
virtual const std::string & getId() const
It returns the layer id.
void onDrawLayerFinished(const int &index, const QImage &image)
virtual QPointF transform(const QPointF &p)
Transforms the given point, in screen coordinates, to a point in world coordinates.
This class represents a thread responsible to draw a given layer. Basically, this class receives draw...
void setExtent(te::gm::Envelope &e, bool doRefresh=true)
It sets the world visible area and refreshes the contents in the map display.
A widget to control the display of a set of layers.
Definition: MapDisplay.h:66
void refresh()
It updates the contents in the map display.
A multi thread Qt4 widget to control the display of a set of layers.
virtual void setExtent(te::gm::Envelope &e, bool doRefresh=true)
It sets the world visible area and refreshes the contents in the map display.
Definition: MapDisplay.cpp:68
CompositionMode
The composition mode used to render the canvas.
Definition: Enums.h:174
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
This class represents a thread responsible to draw a given layer. Basically, this class receives draw...
QString getErrorMessage() const
This method returns an error message if the thread has not finished with success. Otherwise...
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...
bool finishedWithSuccess() const
This method tells if the thread finished with success.
te::map::AbstractLayer * getLayer() const
This method returns the layer handled by this thread.
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
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.
Definition: Utils.cpp:248