All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
WMSLayerRenderer.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/wms/WMSLayerRenderer.cpp
22 
23  \brief It renders the data associated to a WMS layer.
24 */
25 
26 // TerraLib
27 #include "../common/progress/TaskProgress.h"
28 #include "../common/STLUtils.h"
29 #include "../common/Translator.h"
30 #include "../dataaccess/utils/Utils.h"
31 #include "../geometry/Envelope.h"
32 #include "../geometry/Utils.h"
33 #include "../maptools/Canvas.h"
34 #include "../maptools/CanvasConfigurer.h"
35 #include "../maptools/RasterTransform.h"
36 #include "../maptools/RasterTransformConfigurer.h"
37 #include "../raster/Grid.h"
38 #include "../raster/RasterProperty.h"
39 #include "../raster/RasterSummary.h"
40 #include "../raster/RasterSummaryManager.h"
41 #include "../raster/Utils.h"
42 #include "../se/CoverageStyle.h"
43 #include "../se/ImageOutline.h"
44 #include "../se/RasterSymbolizer.h"
45 #include "../se/Rule.h"
46 #include "../se/Utils.h"
47 #include "../srs/Config.h"
48 #include "../srs/Converter.h"
49 #include "Exception.h"
50 #include "WMSLayer.h"
51 #include "WMSLayerRenderer.h"
52 
53 // Boost
54 #include <boost/format.hpp>
55 #include <boost/lexical_cast.hpp>
56 
57 // STL
58 #include <cassert>
59 #include <memory>
60 
62 {
63 }
64 
66 {
67 }
68 
70  te::map::Canvas* canvas,
71  const te::gm::Envelope& bbox,
72  int srid)
73 {
74  if(!bbox.isValid())
75  throw Exception(TE_TR("The requested box is invalid!"));
76 
77  assert(layer);
78  assert(canvas);
79 
80  // Should I render this layer?
81  WMSLayer* wmsLayer = dynamic_cast<WMSLayer*>(layer);
82 
83  if(wmsLayer == 0)
84  throw Exception(TE_TR("Wrong type render type for this layer!"));
85 
86  draw(wmsLayer, canvas, bbox, srid);
87 }
88 
89 void te::wms::WMSLayerRenderer::draw(WMSLayer* layer, te::map::Canvas* canvas, const te::gm::Envelope& bbox, int srid)
90 {
91  // Check if layer extent intersects the drawing area and so compute bounding box intersection
92  te::gm::Envelope reprojectedBBOX(bbox);
93 
94  if((layer->getSRID() != TE_UNKNOWN_SRS) && (srid != TE_UNKNOWN_SRS))
95  {
96  reprojectedBBOX.transform(srid, layer->getSRID());
97  }
98  else if(layer->getSRID() != srid)
99  {
100  throw Exception(TE_TR("The layer or map has no valid SRID!"));
101  }
102 
103  if(!reprojectedBBOX.intersects(layer->getExtent()))
104  return;
105 
106  te::gm::Envelope ibbox = reprojectedBBOX.intersection(layer->getExtent());
107  assert(ibbox.isValid());
108 
109  // Get the layer schema
110  std::auto_ptr<te::map::LayerSchema> schema(layer->getSchema());
111  assert(schema.get());
112 
113  // Get the raster property
114  te::rst::RasterProperty* rasterProperty = te::da::GetFirstRasterProperty(schema.get());
115 
116  // Get the layer style
117  te::se::Style* style = layer->getStyle();
118  if(style == 0)
119  {
120  // Try create an appropriate style. i.e. a CoverageStyle
121  style = te::se::CreateCoverageStyle(rasterProperty->getBandProperties());
122 
123  if(style == 0)
124  throw Exception((boost::format(TE_TR("Could not create a default coverage style for the layer %1%!")) % layer->getTitle()).str());
125 
126  layer->setStyle(style);
127  }
128 
129  // Should I render this style?
130  te::se::CoverageStyle* cs = dynamic_cast<te::se::CoverageStyle*>(style);
131  if(cs == 0)
132  throw Exception(TE_TR("The layer style is not a Coverage Style!"));
133 
134  // Setup the WMS Layer to request data
135  layer->setWidth(canvas->getWidth());
136  layer->setHeight(canvas->getHeight());
137 
138  // Request the WMS data
139  std::auto_ptr<te::da::DataSet> dataset = layer->getData(rasterProperty->getName(), &ibbox, te::gm::INTERSECTS);
140 
141  if(dataset.get() == 0)
142  throw Exception((boost::format(TE_TR("Could not retrieve the WMS data from the layer %1%!")) % layer->getTitle()).str());
143 
144  std::size_t rpos = te::da::GetFirstPropertyPos(dataset.get(), te::dt::RASTER_TYPE);
145 
146  // Retrieve the raster
147  std::auto_ptr<te::rst::Raster> raster(dataset->getRaster(rpos));
148  if(dataset.get() == 0)
149  throw Exception((boost::format(TE_TR("Could not retrieve the WMS data from the layer %1%!")) % layer->getTitle()).str());
150 
151  // Let's draw!
152  drawRaster(layer->getTitle(), raster.get(), canvas, ibbox, layer->getSRID(), bbox, srid, cs);
153 }
154 
155 void te::wms::WMSLayerRenderer::drawRaster(const std::string& layerTitle, te::rst::Raster* raster, te::map::Canvas* canvas, const te::gm::Envelope& bbox, int bboxSRID,
156  const te::gm::Envelope& visibleArea, int srid, te::se::CoverageStyle* style)
157 {
158  assert(raster);
159  assert(canvas);
160  assert(bbox.isValid());
161  assert(visibleArea.isValid());
162  assert(style);
163 
164  // Build the grid canvas. i.e. a grid with canvas dimensions and requested mbr
165  te::gm::Envelope* gmbr = new te::gm::Envelope(visibleArea);
166  std::auto_ptr<te::rst::Grid> gridCanvas(new te::rst::Grid(static_cast<unsigned int>(canvas->getWidth()), static_cast<unsigned int>(canvas->getHeight()), gmbr, srid));
167 
168  // Create a raster transform
169  te::map::RasterTransform rasterTransform(raster, 0);
170 
171  // Check band data type
172  if(raster->getBandDataType(0) != te::dt::UCHAR_TYPE)
173  {
174  // Raster min / max values
177  const std::complex<double>* cmin = rsMin->at(0).m_minVal;
178  const std::complex<double>* cmax = rsMax->at(0).m_maxVal;
179  double min = cmin->real();
180  double max = cmax->real();
181 
182  rasterTransform.setLinearTransfParameters(min, max, 0, 255);
183  }
184  else
185  {
186  rasterTransform.setLinearTransfParameters(0, 255, 0, 255);
187  }
188 
189  // Get the raster symbolizer
190  std::size_t nRules = style->getRules().size();
191  assert(nRules >= 1);
192 
193  // For while, consider one rule
194  const te::se::Rule* rule = style->getRule(0);
195 
196  const std::vector<te::se::Symbolizer*>& symbolizers = rule->getSymbolizers();
197  assert(!symbolizers.empty());
198 
199  // For while, consider one raster symbolizer
200  te::se::RasterSymbolizer* rasterSymbolizer = dynamic_cast<te::se::RasterSymbolizer*>(symbolizers[0]);
201  assert(rasterSymbolizer);
202 
203  // Configure the raster transformation based on the raster symbolizer
204  te::map::RasterTransformConfigurer rtc(rasterSymbolizer, &rasterTransform);
205  rtc.configure();
206 
207  // Adjusting to deal with transparency...
208  if(raster->getNumberOfBands() > 3)
209  {
210  rasterTransform.getRGBMap()[te::map::RasterTransform::ALPHA_CHANNEL] = 3;
211  rasterTransform.setTransfFunction(te::map::RasterTransform::EXTRACT2RGBA_TRANSF);
212  }
213 
214  // Verify if is necessary convert the raster to the given srid
215  bool needRemap = false;
216  if((bboxSRID != TE_UNKNOWN_SRS) && (srid != TE_UNKNOWN_SRS) && (bboxSRID != srid))
217  needRemap = true;
218 
219  // Build task message
220  std::string message = TE_TR("Drawing the WMS layer");
221  !layerTitle.empty() ? message += " " + layerTitle + ". " : message += "...";
222 
223  // Create the draw task
224  te::common::TaskProgress task(message, te::common::TaskProgress::DRAW, gridCanvas->getNumberOfRows());
225 
226  // Create a RGBA array that will be drawn in the canvas. i.e. This array is the result of the render process.
227  //te::color::RGBAColor** rgba = new te::color::RGBAColor*[gridCanvas->getNumberOfRows()];
228 
229  // Create a RGBA array that will be drawn in the canvas. i.e. This array represents a row of the render process.
231  te::color::RGBAColor* columns = new te::color::RGBAColor[gridCanvas->getNumberOfColumns()];
232  row[0] = columns;
233 
234  // Create a SRS converter
235  std::auto_ptr<te::srs::Converter> converter(new te::srs::Converter());
236  if(needRemap)
237  {
238  converter->setSourceSRID(srid);
239  converter->setTargetSRID(bboxSRID);
240  }
241 
242  // Fill the result RGBA array
243  for(unsigned int r = 0; r < gridCanvas->getNumberOfRows(); ++r)
244  {
245  for(unsigned int c = 0; c < gridCanvas->getNumberOfColumns(); ++c)
246  {
247  te::gm::Coord2D inputGeo = gridCanvas->gridToGeo(c, r);
248 
249  if(needRemap)
250  converter->convert(inputGeo.x, inputGeo.y, inputGeo.x, inputGeo.y);
251 
252  te::gm::Coord2D outputGrid = raster->getGrid()->geoToGrid(inputGeo.x, inputGeo.y);
253 
254  // TODO: round or truncate?
255  int x = te::rst::Round(outputGrid.x);
256  int y = te::rst::Round(outputGrid.y);
257 
258  te::color::RGBAColor color(255, 255, 255, 0);
259 
260  if((x >= 0 && x < (int)(raster->getNumberOfColumns())) &&
261  (y >= 0 && y < (int)(raster->getNumberOfRows())))
262  color = rasterTransform.apply(x, y);
263 
264  columns[c] = color;
265  }
266 
267  //rgba[r] = columns;
268 
269  if(!task.isActive())
270  {
271  // Draw the part of result
272  //canvas->drawImage(0, 0, rgba, canvas->getWidth(), r + 1);
273  canvas->drawImage(0, r, row, canvas->getWidth(), 1);
274 
275  // Free memory
276  //te::common::Free(rgba, r + 1);
277  te::common::Free(row, 1);
278 
279  return;
280  }
281 
282  canvas->drawImage(0, r, row, canvas->getWidth(), 1);
283 
284  task.pulse();
285  }
286 
287  // Put the result in the canvas
288  //canvas->drawImage(0, 0, rgba, canvas->getWidth(), canvas->getHeight());
289 
290  // Free memory
291  //te::common::Free(rgba, gridCanvas->getNumberOfRows());
292  te::common::Free(row, 1);
293 
294  // Image outline
295  if(rasterSymbolizer->getImageOutline() == 0)
296  return;
297 
298  // Get the symbolizer that will be used to draw the image outline
299  te::se::Symbolizer* outlineSymbolizer = rasterSymbolizer->getImageOutline()->getSymbolizer();
300  if(outlineSymbolizer == 0)
301  return;
302 
303  // Create a canvas configurer
304  te::map::CanvasConfigurer cc(canvas);
305  cc.config(outlineSymbolizer);
306 
307  // Creates the image outline
308  std::auto_ptr<te::gm::Geometry> geom(te::gm::GetGeomFromEnvelope(raster->getExtent(), bboxSRID));
309  if(needRemap)
310  {
311  geom->setSRID(bboxSRID);
312  geom->transform(srid);
313  }
314 
315  canvas->draw(geom.get());
316 }
A layer with reference to a WMS Layer.
It renders the data associated to a WMS layer.
te::gm::Envelope * getExtent()
Returns the geographic extension of the raster data.
Definition: Raster.cpp:104
TEDATAACCESSEXPORT te::rst::RasterProperty * GetFirstRasterProperty(const DataSetType *dt)
Definition: Utils.cpp:571
std::auto_ptr< te::map::LayerSchema > getSchema() const
It returns the layer schema.
Definition: WMSLayer.cpp:76
double y
y-coordinate.
Definition: Coord2D.h:114
bool intersects(const Envelope &rhs) const
It returns true if the envelopes "spatially intersects".
Definition: Envelope.h:493
The Style defines the styling that is to be applied to a geographic dataset (vector geometries or cov...
Definition: Style.h:65
This is the base class for layers.
Definition: AbstractLayer.h:76
virtual const te::gm::Envelope & getExtent() const
It returns the Layer extent (or minimum bounding box).
virtual const std::string & getTitle() const
It returns the layer title.
double x
x-coordinate.
Definition: Coord2D.h:113
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
Definition: Raster.cpp:213
A Symbolizer describes how a feature is to appear on a map.
Definition: Symbolizer.h:80
std::auto_ptr< te::da::DataSet > getData(te::common::TraverseType travType=te::common::FORWARDONLY, const te::common::AccessPolicy accessPolicy=te::common::RAccess) const
It gets the dataset identified by the layer name.
Definition: WMSLayer.cpp:90
virtual int getHeight() const =0
It returns the canvas height.
The CoverageStyle defines the styling that is to be applied to a subset of Coverage data...
Definition: CoverageStyle.h:45
void configure()
Configure Transformation.
TESEEXPORT Style * CreateCoverageStyle(const std::vector< te::rst::BandProperty * > &properties)
Try creates an appropriate coverage style based on given band properties.
Definition: Utils.cpp:299
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
virtual int getWidth() const =0
It returns the canvas width.
An utility struct for representing 2D coordinates.
Definition: Coord2D.h:40
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:347
Raster property.
void geoToGrid(const double &x, const double &y, double &col, double &row) const
Get the grid point associated to a spatial location.
Definition: Grid.cpp:307
Rule * getRule(std::size_t i) const
Definition: Style.cpp:105
const std::vector< Rule * > & getRules() const
Definition: Style.cpp:94
void Free(std::vector< T * > *v)
This function can be applied to a pointer to a vector of pointers.
Definition: STLUtils.h:131
A layer with reference to a WMS Layer.
Definition: WMSLayer.h:45
An exception class for the TerraLib WMS module.
static RasterSummaryManager & getInstance()
It returns a reference to the singleton instance.
TERASTEREXPORT int Round(double val)
Round a double value to a integer value.
Definition: Utils.cpp:298
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
Definition: Config.h:44
An abstract class for raster data strucutures.
Definition: Raster.h:71
unsigned int getNumberOfRows() const
Returns the raster number of rows.
Definition: Raster.cpp:208
virtual te::se::Style * getStyle() const
It returns the Style associated to the layer.
void setWidth(const std::size_t &width)
Definition: WMSLayer.cpp:212
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
boost::ptr_vector< BandSummary > RasterSummary
RasterSummary is just a typedef of a boost::ptr_vector.
Definition: RasterSummary.h:44
The RasterSymbolizer describes how to render raster/matrix-coverage data (e.g., satellite photos...
virtual void drawImage(char *src, std::size_t size, ImageType t)=0
It draws the src image over the canvas.
Grid * getGrid()
It returns the raster grid.
Definition: Raster.cpp:94
void draw(te::map::AbstractLayer *layer, te::map::Canvas *canvas, const te::gm::Envelope &bbox, int srid)
It draws the layer geographic objects in the given canvas using the SRS informed. ...
const std::vector< Symbolizer * > & getSymbolizers() const
Definition: Rule.cpp:158
A Converter is responsible for the conversion of coordinates between different Coordinate Systems (CS...
Definition: Converter.h:53
A canvas is an abstraction of a drawing area.
Definition: Canvas.h:91
A Rule is used to attach property/scale conditions to and group the individual symbols used for rende...
Definition: Rule.h:78
virtual void setStyle(te::se::Style *style)
It sets the Style associated to the layer.
A helper class for 32-bit RGBA (Red-Green-Blue-Alpha channel) color.
Definition: RGBAColor.h:57
A Raster Transform configurer generates a Raster Transform given a RasterSymbolzier.
virtual int getSRID() const
It returns the Spatial Reference System ID associated to the Layer.
void drawRaster(const std::string &layerTitle, te::rst::Raster *raster, te::map::Canvas *canvas, const te::gm::Envelope &bbox, int bboxSRID, const te::gm::Envelope &visibleArea, int srid, te::se::CoverageStyle *style)
A Raster Transform is a class that defines functions to transform a styled raster.
TEDATAACCESSEXPORT std::size_t GetFirstPropertyPos(const te::da::DataSet *dataset, int datatype)
Definition: Utils.cpp:481
void config(const te::se::Symbolizer *symbolizer)
It configs the canvas based on given symbolizer.
Envelope intersection(const Envelope &rhs) const
It returns an envelope that represents the point set intersection with another envelope.
Definition: Envelope.h:543
Calculate the min value.
Definition: Enums.h:40
A rectified grid is the spatial support for raster data.
Definition: Grid.h:68
Calculate the max value.
Definition: Enums.h:41
void transform(int oldsrid, int newsrid)
It will transform the coordinates of the Envelope from the old SRS to the new one.
Definition: Envelope.cpp:92
virtual int getBandDataType(std::size_t i) const =0
Returns the data type in a particular band (or dimension).
virtual void draw(const te::gm::Geometry *geom)=0
It draws the geometry on canvas.
bool isValid() const
It tells if the rectangle is valid or not.
Definition: Envelope.h:438
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
Definition: Utils.cpp:38
A Symbology Enconding visitor that configures a given canvas based on symbolizers elements...
void setHeight(const std::size_t &height)
Definition: WMSLayer.cpp:217