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) 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/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 {
41  setAttribute(Qt::WA_OpaquePaintEvent, true);
42 }
43 
45 {
46  te::common::FreeContents(m_threads);
47 }
48 
50 {
51  if(m_isDrawing)
52  return;
53 
55 
56  updateTransform();
57 
58  e = m_extent;
59 
60  if(doRefresh)
61  refresh();
62 
63  emit extentChanged();
64 }
65 
67 {
68  if(m_isDrawing)
69  return;
70 
71  // Cleaning...
72  m_displayPixmap->fill(m_backgroundColor);
73  m_draftPixmap->fill(Qt::transparent);
74 
75  // Considering only the visible layers
76  m_visibleLayers.clear();
77  te::map::GetVisibleLayers(m_layerList, m_visibleLayers);
78 
79  if(m_visibleLayers.empty())
80  {
81  repaint();
82  return;
83  }
84 
85  int n = m_visibleLayers.size() - m_threads.size();
86  for(int i = 0; i < n; ++i)
87  {
88  DrawLayerThread* thread = new DrawLayerThread;
89 
90  if(m_showFeedback) // Do you want show feedbacks?
91  connect(thread, SIGNAL(feedback(QImage)), this, SLOT(showFeedback(QImage)));
92 
93  connect(thread, SIGNAL(drawLayerFinished(int, QImage)), this, SLOT(onDrawLayerFinished(int, QImage)));
94 
95  m_threads.push_back(thread);
96  }
97 
98  QApplication::setOverrideCursor(Qt::WaitCursor);
99 
100  m_isDrawing = true;
101 
102  std::size_t i = 0;
103  std::list<te::map::AbstractLayerPtr>::reverse_iterator it;
104  for(it = m_visibleLayers.rbegin(); it != m_visibleLayers.rend(); ++it) // for each layer
105  {
106  m_threads[i]->draw(it->get(), m_extent, m_srid, size(), i);
107  i++;
108  }
109 }
110 
112 {
113  if(!m_extent.isValid())
114  return QPointF();
115 
116  return m_matrix.inverted().map(p);
117 }
118 
120 {
121  if(!m_extent.isValid())
122  return;
123 
124  // Compute aspect ratio
125  double ww = m_extent.m_urx - m_extent.m_llx;
126  double wh = m_extent.m_ury - m_extent.m_lly;
127 
128  double widthByHeight = static_cast<double>(width()) / static_cast<double>(height());
129 
130  if(widthByHeight > ww / wh)
131  {
132  double v = ww;
133  ww = wh * widthByHeight;
134  m_extent.m_llx = m_extent.m_llx - (ww - v) * 0.5;
135  m_extent.m_urx = m_extent.m_llx + ww;
136  }
137  else
138  {
139  double v = wh;
140  wh = ww / widthByHeight;
141  m_extent.m_lly = m_extent.m_lly - (wh - v) * 0.5;
142  m_extent.m_ury = m_extent.m_lly + wh;
143  }
144 
145  // Bulding the transform matrix
146  double xScale = static_cast<double>(width()) / (m_extent.m_urx - m_extent.m_llx);
147  double yScale = static_cast<double>(height()) / (m_extent.m_ury - m_extent.m_lly);
148  m_matrix.reset();
149  m_matrix.scale(xScale, -yScale);
150  m_matrix.translate(-m_extent.m_llx, -m_extent.m_ury);
151 }
152 
154 {
155  QPainter painter(m_displayPixmap);
156  painter.setOpacity(0.1); // To improve user visual experience!
157  //painter.drawImage(0, 0, image);
158  painter.drawPixmap(0, 0, QPixmap::fromImage(image));
159  repaint(); // or update()? Which is the best here?!
160 }
161 
162 void te::qt::widgets::MultiThreadMapDisplay::onDrawLayerFinished(const int& index, const QImage& image)
163 {
164  m_images.insert(std::pair<int, QImage>(index, image));
165  if(m_images.size() != m_visibleLayers.size())
166  {
167  QPainter painter(m_displayPixmap);
168  //painter.drawImage(0, 0, image);
169  painter.drawPixmap(0, 0, QPixmap::fromImage(image));
170  painter.end();
171 
172  repaint();
173 
174  return;
175  }
176 
177  m_displayPixmap->fill(m_backgroundColor);
178 
179  QPainter painter(m_displayPixmap);
180 
181  std::map<int, QImage>::iterator it;
182  for(it = m_images.begin(); it != m_images.end(); ++it)
183  painter.drawPixmap(0, 0, QPixmap::fromImage(it->second));
184  //painter.drawImage(0, 0, it->second);
185 
186  painter.end();
187 
188  m_images.clear();
189 
190  repaint(); // or update()? Which is the best here?!
191 
192  m_isDrawing = false;
193 
194  QApplication::restoreOverrideCursor();
195 
196  // Building the error messages
197  QMap<QString, QString> errors;
198  for(std::size_t i = 0; i < m_threads.size(); ++i)
199  {
200  DrawLayerThread* t = m_threads[i];
201  if(t->finishedWithSuccess())
202  continue;
203  errors.insert(t->getLayer()->getId().c_str(), t->getErrorMessage());
204  }
205 
206  emit drawLayersFinished(errors);
207 }
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:65
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
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