attic/src/wms/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 "../core/translator/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  const double& scale, bool* cancel)
74 {
75  if(!bbox.isValid())
76  throw Exception(TE_TR("The requested box is invalid!"));
77 
78  assert(layer);
79  assert(canvas);
80 
81  // Should I render this layer?
82  WMSLayer* wmsLayer = dynamic_cast<WMSLayer*>(layer);
83 
84  if(wmsLayer == 0)
85  throw Exception(TE_TR("Wrong type render type for this layer!"));
86 
87  draw(wmsLayer, canvas, bbox, srid);
88 }
89 
90 void te::wms::WMSLayerRenderer::draw(WMSLayer* layer, te::map::Canvas* canvas, const te::gm::Envelope& bbox, int srid)
91 {
92  // Check if layer extent intersects the drawing area and so compute bounding box intersection
93  te::gm::Envelope reprojectedBBOX(bbox);
94 
95  if((layer->getSRID() != TE_UNKNOWN_SRS) && (srid != TE_UNKNOWN_SRS))
96  {
97  reprojectedBBOX.transform(srid, layer->getSRID());
98  }
99  else if(layer->getSRID() != srid)
100  {
101  throw Exception(TE_TR("The layer or map has no valid SRID!"));
102  }
103 
104  if(!reprojectedBBOX.intersects(layer->getExtent()))
105  return;
106 
107  te::gm::Envelope ibbox = reprojectedBBOX.intersection(layer->getExtent());
108  assert(ibbox.isValid());
109 
110  // Get the layer schema
111  std::auto_ptr<te::map::LayerSchema> schema(layer->getSchema());
112  assert(schema.get());
113 
114  // Get the raster property
115  te::rst::RasterProperty* rasterProperty = te::da::GetFirstRasterProperty(schema.get());
116 
117  // Get the layer style
118  te::se::Style* style = layer->getStyle();
119  if(style == 0)
120  {
121  // Try create an appropriate style. i.e. a CoverageStyle
122  style = te::se::CreateCoverageStyle(rasterProperty->getBandProperties());
123 
124  if(style == 0)
125  throw Exception((boost::format(TE_TR("Could not create a default coverage style for the layer %1%!")) % layer->getTitle()).str());
126 
127  layer->setStyle(style);
128  }
129 
130  // Should I render this style?
131  te::se::CoverageStyle* cs = dynamic_cast<te::se::CoverageStyle*>(style);
132  if(cs == 0)
133  throw Exception(TE_TR("The layer style is not a Coverage Style!"));
134 
135  // Setup the WMS Layer to request data
136  layer->setWidth(canvas->getWidth());
137  layer->setHeight(canvas->getHeight());
138 
139  // Request the WMS data
140  std::auto_ptr<te::da::DataSet> dataset = layer->getData(rasterProperty->getName(), &ibbox, te::gm::INTERSECTS);
141 
142  if(dataset.get() == 0)
143  throw Exception((boost::format(TE_TR("Could not retrieve the WMS data from the layer %1%!")) % layer->getTitle()).str());
144 
145  std::size_t rpos = te::da::GetFirstPropertyPos(dataset.get(), te::dt::RASTER_TYPE);
146 
147  // Retrieve the raster
148  std::auto_ptr<te::rst::Raster> raster(dataset->getRaster(rpos));
149  if(dataset.get() == 0)
150  throw Exception((boost::format(TE_TR("Could not retrieve the WMS data from the layer %1%!")) % layer->getTitle()).str());
151 
152  // Let's draw!
153  drawRaster(layer->getTitle(), raster.get(), canvas, ibbox, layer->getSRID(), bbox, srid, cs);
154 }
155 
156 void te::wms::WMSLayerRenderer::drawRaster(const std::string& layerTitle, te::rst::Raster* raster, te::map::Canvas* canvas, const te::gm::Envelope& bbox, int bboxSRID,
157  const te::gm::Envelope& visibleArea, int srid, te::se::CoverageStyle* style)
158 {
159  assert(raster);
160  assert(canvas);
161  assert(bbox.isValid());
162  assert(visibleArea.isValid());
163  assert(style);
164 
165  // Build the grid canvas. i.e. a grid with canvas dimensions and requested mbr
166  te::gm::Envelope* gmbr = new te::gm::Envelope(visibleArea);
167  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));
168 
169  // Create a raster transform
170  te::map::RasterTransform rasterTransform(raster, 0);
171 
172  // Check band data type
173  if(raster->getBandDataType(0) != te::dt::UCHAR_TYPE)
174  {
175  // Raster min / max values
178  const std::complex<double>* cmin = rsMin->at(0).m_minVal;
179  const std::complex<double>* cmax = rsMax->at(0).m_maxVal;
180  double min = cmin->real();
181  double max = cmax->real();
182 
183  rasterTransform.setLinearTransfParameters(min, max, 0, 255);
184  }
185  else
186  {
187  rasterTransform.setLinearTransfParameters(0, 255, 0, 255);
188  }
189 
190  // Get the raster symbolizer
191  std::size_t nRules = style->getRules().size();
192  assert(nRules >= 1);
193 
194  // For while, consider one rule
195  const te::se::Rule* rule = style->getRule(0);
196 
197  const std::vector<te::se::Symbolizer*>& symbolizers = rule->getSymbolizers();
198  assert(!symbolizers.empty());
199 
200  // For while, consider one raster symbolizer
201  te::se::RasterSymbolizer* rasterSymbolizer = dynamic_cast<te::se::RasterSymbolizer*>(symbolizers[0]);
202  assert(rasterSymbolizer);
203 
204  // Configure the raster transformation based on the raster symbolizer
205  te::map::RasterTransformConfigurer rtc(rasterSymbolizer, &rasterTransform);
206  rtc.configure();
207 
208  // Adjusting to deal with transparency...
209  if(raster->getNumberOfBands() > 3)
210  {
211  rasterTransform.getRGBMap()[te::map::RasterTransform::ALPHA_CHANNEL] = 3;
212  rasterTransform.setTransfFunction(te::map::RasterTransform::EXTRACT2RGBA_TRANSF);
213  }
214 
215  // Verify if is necessary convert the raster to the given srid
216  bool needRemap = false;
217  if((bboxSRID != TE_UNKNOWN_SRS) && (srid != TE_UNKNOWN_SRS) && (bboxSRID != srid))
218  needRemap = true;
219 
220  // Build task message
221  std::string message = TE_TR("Drawing the WMS layer");
222  !layerTitle.empty() ? message += " " + layerTitle + ". " : message += "...";
223 
224  // Create the draw task
225  te::common::TaskProgress task(message, te::common::TaskProgress::DRAW, gridCanvas->getNumberOfRows());
226 
227  // Create a RGBA array that will be drawn in the canvas. i.e. This array is the result of the render process.
228  //te::color::RGBAColor** rgba = new te::color::RGBAColor*[gridCanvas->getNumberOfRows()];
229 
230  // Create a RGBA array that will be drawn in the canvas. i.e. This array represents a row of the render process.
232  te::color::RGBAColor* columns = new te::color::RGBAColor[gridCanvas->getNumberOfColumns()];
233  row[0] = columns;
234 
235  // Create a SRS converter
236  std::auto_ptr<te::srs::Converter> converter(new te::srs::Converter());
237  if(needRemap)
238  {
239  converter->setSourceSRID(srid);
240  converter->setTargetSRID(bboxSRID);
241  }
242 
243  // Fill the result RGBA array
244  for(unsigned int r = 0; r < gridCanvas->getNumberOfRows(); ++r)
245  {
246  for(unsigned int c = 0; c < gridCanvas->getNumberOfColumns(); ++c)
247  {
248  te::gm::Coord2D inputGeo = gridCanvas->gridToGeo(c, r);
249 
250  if(needRemap)
251  converter->convert(inputGeo.x, inputGeo.y, inputGeo.x, inputGeo.y);
252 
253  te::gm::Coord2D outputGrid = raster->getGrid()->geoToGrid(inputGeo.x, inputGeo.y);
254 
255  // TODO: round or truncate?
256  int x = te::rst::Round(outputGrid.x);
257  int y = te::rst::Round(outputGrid.y);
258 
259  te::color::RGBAColor color(255, 255, 255, 0);
260 
261  if((x >= 0 && x < (int)(raster->getNumberOfColumns())) &&
262  (y >= 0 && y < (int)(raster->getNumberOfRows())))
263  color = rasterTransform.apply(x, y);
264 
265  columns[c] = color;
266  }
267 
268  //rgba[r] = columns;
269 
270  if(!task.isActive())
271  {
272  // Draw the part of result
273  //canvas->drawImage(0, 0, rgba, canvas->getWidth(), r + 1);
274  canvas->drawImage(0, r, row, canvas->getWidth(), 1);
275 
276  // Free memory
277  //te::common::Free(rgba, r + 1);
278  te::common::Free(row, 1);
279 
280  return;
281  }
282 
283  canvas->drawImage(0, r, row, canvas->getWidth(), 1);
284 
285  task.pulse();
286  }
287 
288  // Put the result in the canvas
289  //canvas->drawImage(0, 0, rgba, canvas->getWidth(), canvas->getHeight());
290 
291  // Free memory
292  //te::common::Free(rgba, gridCanvas->getNumberOfRows());
293  te::common::Free(row, 1);
294 
295  // Image outline
296  if(rasterSymbolizer->getImageOutline() == 0)
297  return;
298 
299  // Get the symbolizer that will be used to draw the image outline
300  te::se::Symbolizer* outlineSymbolizer = rasterSymbolizer->getImageOutline()->getSymbolizer();
301  if(outlineSymbolizer == 0)
302  return;
303 
304  // Create a canvas configurer
305  te::map::CanvasConfigurer cc(canvas);
306  cc.config(outlineSymbolizer);
307 
308  // Creates the image outline
309  std::auto_ptr<te::gm::Geometry> geom(te::gm::GetGeomFromEnvelope(raster->getExtent(), bboxSRID));
310  if(needRemap)
311  {
312  geom->setSRID(bboxSRID);
313  geom->transform(srid);
314  }
315 
316  canvas->draw(geom.get());
317 }
te::gm::Envelope * getExtent()
Returns the geographic extension of the raster data.
TEDATAACCESSEXPORT te::rst::RasterProperty * GetFirstRasterProperty(const DataSetType *dt)
std::auto_ptr< te::map::LayerSchema > getSchema() const
It returns the layer schema.
double y
y-coordinate.
Definition: Coord2D.h:114
bool intersects(const Envelope &rhs) const
It returns true if the envelopes "spatially intersects".
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:77
virtual const te::gm::Envelope & getExtent() const
It returns the Layer extent (or minimum bounding box).
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
virtual const std::string & getTitle() const
It returns the layer title.
double x
x-coordinate.
Definition: Coord2D.h:113
Base exception class for plugin module.
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
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.
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.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
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:242
Raster property.
void geoToGrid(const double &x, const double &y, double &col, double &row) const
Get the grid point associated to a spatial location.
Rule * getRule(std::size_t i) const
Definition: Style.cpp:105
const std::vector< Rule * > & getRules() const
Definition: Style.cpp:94
void draw(te::map::AbstractLayer *layer, te::map::Canvas *canvas, const te::gm::Envelope &bbox, int srid, const double &scale, bool *cancel)
It draws the layer geographic objects in the given canvas using the SRS informed. ...
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.
static RasterSummaryManager & getInstance()
It returns a reference to the singleton instance.
An Envelope defines a 2D rectangular region.
An abstract class for raster data strucutures.
unsigned int getNumberOfRows() const
Returns the raster number of rows.
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
virtual te::se::Style * getStyle() const
It returns the Style associated to the layer.
void setWidth(const std::size_t &width)
TERASTEREXPORT int Round(double val)
Round a double value to a integer value.
virtual int getHeight() const =0
It returns the canvas height.
virtual int getBandDataType(std::size_t i) const =0
Returns the data type in a particular band (or dimension).
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.
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.
A Rule is used to attach property/scale conditions to and group the individual symbols used for rende...
Definition: Rule.h:76
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)
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.
Calculate the min value.
A rectified grid is the spatial support for raster data.
Definition: raster/Grid.h:68
Calculate the max value.
void transform(int oldsrid, int newsrid)
It will transform the coordinates of the Envelope from the old SRS to the new one.
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.
virtual int getWidth() const =0
It returns the canvas width.
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
A Symbology Enconding visitor that configures a given canvas based on symbolizers elements...
void setHeight(const std::size_t &height)