Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsrendererv2.cpp
Go to the documentation of this file.
1 
2 #include "qgsrendererv2.h"
3 #include "qgssymbolv2.h"
5 
6 #include "qgssinglesymbolrendererv2.h" // for default renderer
7 
9 
10 #include "qgsrendercontext.h"
11 #include "qgsclipper.h"
12 #include "qgsgeometry.h"
13 #include "qgsfeature.h"
14 #include "qgslogger.h"
15 #include "qgsvectorlayer.h"
16 
17 #include <QDomElement>
18 #include <QDomDocument>
19 #include <QPolygonF>
20 
21 
22 
23 unsigned char* QgsFeatureRendererV2::_getPoint( QPointF& pt, QgsRenderContext& context, unsigned char* wkb )
24 {
25  wkb++; // jump over endian info
26  unsigned int wkbType = *(( int* ) wkb );
27  wkb += sizeof( unsigned int );
28 
29  double x = *(( double * ) wkb ); wkb += sizeof( double );
30  double y = *(( double * ) wkb ); wkb += sizeof( double );
31 
32  if ( wkbType == QGis::WKBPolygon25D )
33  wkb += sizeof( double );
34 
35  if ( context.coordinateTransform() )
36  {
37  double z = 0; // dummy variable for coordiante transform
38  context.coordinateTransform()->transformInPlace( x, y, z );
39  }
40 
41  context.mapToPixel().transformInPlace( x, y );
42 
43  pt = QPointF( x, y );
44  return wkb;
45 }
46 
47 unsigned char* QgsFeatureRendererV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, unsigned char* wkb )
48 {
49  wkb++; // jump over endian info
50  unsigned int wkbType = *(( int* ) wkb );
51  wkb += sizeof( unsigned int );
52  unsigned int nPoints = *(( int* ) wkb );
53  wkb += sizeof( unsigned int );
54 
55  bool hasZValue = ( wkbType == QGis::WKBLineString25D );
56  double x, y, z;
57 
58  const QgsCoordinateTransform* ct = context.coordinateTransform();
59  const QgsMapToPixel& mtp = context.mapToPixel();
60 
61  //apply clipping for large lines to achieve a better rendering performance
62  if ( nPoints > 100 )
63  {
64  const QgsRectangle& e = context.extent();
65  double cw = e.width() / 10; double ch = e.height() / 10;
66  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
67  wkb = QgsClipper::clippedLineWKB( wkb - ( 2 * sizeof( unsigned int ) + 1 ), clipRect, pts );
68  }
69  else
70  {
71  pts.resize( nPoints );
72 
73  for ( unsigned int i = 0; i < nPoints; ++i )
74  {
75  x = *(( double * ) wkb );
76  wkb += sizeof( double );
77  y = *(( double * ) wkb );
78  wkb += sizeof( double );
79 
80  if ( hasZValue ) // ignore Z value
81  wkb += sizeof( double );
82 
83  pts[i] = QPointF( x, y );
84  }
85  }
86 
87  //transform the QPolygonF to screen coordinates
88  for ( int i = 0; i < pts.size(); ++i )
89  {
90  if ( ct )
91  {
92  z = 0;
93  ct->transformInPlace( pts[i].rx(), pts[i].ry(), z );
94  }
95  mtp.transformInPlace( pts[i].rx(), pts[i].ry() );
96  }
97 
98 
99  return wkb;
100 }
101 
102 unsigned char* QgsFeatureRendererV2::_getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, unsigned char* wkb )
103 {
104  wkb++; // jump over endian info
105  unsigned int wkbType = *(( int* ) wkb );
106  wkb += sizeof( unsigned int ); // jump over wkb type
107  unsigned int numRings = *(( int* ) wkb );
108  wkb += sizeof( unsigned int );
109 
110  if ( numRings == 0 ) // sanity check for zero rings in polygon
111  return wkb;
112 
113  bool hasZValue = ( wkbType == QGis::WKBPolygon25D );
114  double x, y;
115  holes.clear();
116 
117  const QgsCoordinateTransform* ct = context.coordinateTransform();
118  const QgsMapToPixel& mtp = context.mapToPixel();
119  double z = 0; // dummy variable for coordiante transform
120 
121  const QgsRectangle& e = context.extent();
122  double cw = e.width() / 10; double ch = e.height() / 10;
123  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
124 
125  for ( unsigned int idx = 0; idx < numRings; idx++ )
126  {
127  unsigned int nPoints = *(( int* )wkb );
128  wkb += sizeof( unsigned int );
129 
130  QPolygonF poly( nPoints );
131 
132  // Extract the points from the WKB and store in a pair of vectors.
133  for ( unsigned int jdx = 0; jdx < nPoints; jdx++ )
134  {
135  x = *(( double * ) wkb ); wkb += sizeof( double );
136  y = *(( double * ) wkb ); wkb += sizeof( double );
137 
138  poly[jdx] = QPointF( x, y );
139 
140  if ( hasZValue )
141  wkb += sizeof( double );
142  }
143 
144  if ( nPoints < 1 )
145  continue;
146 
147  //clip close to view extent
148  QgsClipper::trimPolygon( poly, clipRect );
149 
150  //transform the QPolygonF to screen coordinates
151  for ( int i = 0; i < poly.size(); ++i )
152  {
153  if ( ct )
154  {
155  z = 0;
156  ct->transformInPlace( poly[i].rx(), poly[i].ry(), z );
157  }
158  mtp.transformInPlace( poly[i].rx(), poly[i].ry() );
159  }
160 
161  if ( idx == 0 )
162  pts = poly;
163  else
164  holes.append( poly );
165  }
166 
167  return wkb;
168 }
169 
170 
172  : mType( type ), mUsingSymbolLevels( false ),
173  mCurrentVertexMarkerType( QgsVectorLayer::Cross ),
174  mCurrentVertexMarkerSize( 3 )
175 {
176 }
177 
179 {
180  return new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geomType ) );
181 }
182 
183 
184 void QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
185 {
186  QgsSymbolV2* symbol = symbolForFeature( feature );
187  if ( symbol == NULL )
188  return;
189 
190  QgsSymbolV2::SymbolType symbolType = symbol->type();
191 
192  QgsGeometry* geom = feature.geometry();
193  switch ( geom->wkbType() )
194  {
195  case QGis::WKBPoint:
196  case QGis::WKBPoint25D:
197  {
198  if ( symbolType != QgsSymbolV2::Marker )
199  {
200  QgsDebugMsg( "point can be drawn only with marker symbol!" );
201  break;
202  }
203  QPointF pt;
204  _getPoint( pt, context, geom->asWkb() );
205  (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, context, layer, selected );
206 
207  //if ( drawVertexMarker )
208  // renderVertexMarker( pt, context );
209  }
210  break;
211 
212  case QGis::WKBLineString:
214  {
215  if ( symbolType != QgsSymbolV2::Line )
216  {
217  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
218  break;
219  }
220  QPolygonF pts;
221  _getLineString( pts, context, geom->asWkb() );
222  (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, context, layer, selected );
223 
224  if ( drawVertexMarker )
225  renderVertexMarkerPolyline( pts, context );
226  }
227  break;
228 
229  case QGis::WKBPolygon:
230  case QGis::WKBPolygon25D:
231  {
232  if ( symbolType != QgsSymbolV2::Fill )
233  {
234  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
235  break;
236  }
237  QPolygonF pts;
238  QList<QPolygonF> holes;
239  _getPolygon( pts, holes, context, geom->asWkb() );
240  (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), context, layer, selected );
241 
242  if ( drawVertexMarker )
243  renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context );
244  }
245  break;
246 
247  case QGis::WKBMultiPoint:
249  {
250  if ( symbolType != QgsSymbolV2::Marker )
251  {
252  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
253  break;
254  }
255 
256  unsigned char* wkb = geom->asWkb();
257  unsigned int num = *(( int* )( wkb + 5 ) );
258  unsigned char* ptr = wkb + 9;
259  QPointF pt;
260 
261  for ( unsigned int i = 0; i < num; ++i )
262  {
263  ptr = _getPoint( pt, context, ptr );
264  (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, context, layer, selected );
265 
266  //if ( drawVertexMarker )
267  // renderVertexMarker( pt, context );
268  }
269  }
270  break;
271 
274  {
275  if ( symbolType != QgsSymbolV2::Line )
276  {
277  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
278  break;
279  }
280 
281  unsigned char* wkb = geom->asWkb();
282  unsigned int num = *(( int* )( wkb + 5 ) );
283  unsigned char* ptr = wkb + 9;
284  QPolygonF pts;
285 
286  for ( unsigned int i = 0; i < num; ++i )
287  {
288  ptr = _getLineString( pts, context, ptr );
289  (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, context, layer, selected );
290 
291  if ( drawVertexMarker )
292  renderVertexMarkerPolyline( pts, context );
293  }
294  }
295  break;
296 
299  {
300  if ( symbolType != QgsSymbolV2::Fill )
301  {
302  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
303  break;
304  }
305 
306  unsigned char* wkb = geom->asWkb();
307  unsigned int num = *(( int* )( wkb + 5 ) );
308  unsigned char* ptr = wkb + 9;
309  QPolygonF pts;
310  QList<QPolygonF> holes;
311 
312  for ( unsigned int i = 0; i < num; ++i )
313  {
314  ptr = _getPolygon( pts, holes, context, ptr );
315  (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), context, layer, selected );
316 
317  if ( drawVertexMarker )
318  renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context );
319  }
320  }
321  break;
322 
323  default:
324  QgsDebugMsg( "unsupported wkb type for rendering" );
325  }
326 }
327 
329 {
330  return "UNKNOWN RENDERER\n";
331 }
332 
333 
335 {
336  // <renderer-v2 type=""> ... </renderer-v2>
337 
338  if ( element.isNull() )
339  return NULL;
340 
341  // load renderer
342  QString rendererType = element.attribute( "type" );
343 
345  if ( m == NULL )
346  return NULL;
347 
348  QgsFeatureRendererV2* r = m->createRenderer( element );
349  if ( r )
350  {
351  r->setUsingSymbolLevels( element.attribute( "symbollevels", "0" ).toInt() );
352  r->setUsingFirstRule( element.attribute( "firstrule", "0" ).toInt() );
353  }
354  return r;
355 }
356 
357 QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
358 {
359  // create empty renderer element
360  return doc.createElement( RENDERER_TAG_NAME );
361 }
362 
364 {
365  // empty list by default
366  return QgsLegendSymbologyList();
367 }
368 
370 {
371  return QgsLegendSymbolList();
372 }
373 
375 {
378 }
379 
381 {
382  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(),
385 }
386 
388 {
389  foreach( QPointF pt, pts )
390  renderVertexMarker( pt, context );
391 }
392 
393 void QgsFeatureRendererV2::renderVertexMarkerPolygon( QPolygonF& pts, QList<QPolygonF>* rings, QgsRenderContext& context )
394 {
395  foreach( QPointF pt, pts )
396  renderVertexMarker( pt, context );
397 
398  if ( rings )
399  {
400  foreach( QPolygonF ring, *rings )
401  {
402  foreach( QPointF pt, ring )
403  renderVertexMarker( pt, context );
404  }
405  }
406 }