Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
1 #include "qgsfillsymbollayerv2.h"
4 
5 #include "qgsrendercontext.h"
6 #include "qgsproject.h"
7 
8 #include <QPainter>
9 #include <QFile>
10 #include <QSvgRenderer>
11 
12 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
13  : mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth )
14 {
15  mColor = color;
16 }
17 
18 
20 {
22  Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
26  QPointF offset;
27 
28  if ( props.contains( "color" ) )
29  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
30  if ( props.contains( "style" ) )
31  style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
32  if ( props.contains( "color_border" ) )
33  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
34  if ( props.contains( "style_border" ) )
35  borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
36  if ( props.contains( "width_border" ) )
37  borderWidth = props["width_border"].toDouble();
38  if ( props.contains( "offset" ) )
39  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
40 
41  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth );
42  sl->setOffset( offset );
43  return sl;
44 }
45 
46 
48 {
49  return "SimpleFill";
50 }
51 
53 {
54  mColor.setAlphaF( context.alpha() );
55  mBrush = QBrush( mColor, mBrushStyle );
56 
57  // scale brush content for printout
58  double rasterScaleFactor = context.renderContext().rasterScaleFactor();
59  if ( rasterScaleFactor != 1.0 )
60  {
61  mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
62  }
63 
64  QColor selColor = context.selectionColor();
65  // selColor.setAlphaF( context.alpha() );
66  mSelBrush = QBrush( selColor );
67  if ( selectFillStyle ) mSelBrush.setStyle( mBrushStyle );
68  mBorderColor.setAlphaF( context.alpha() );
69  mPen = QPen( mBorderColor );
70  mPen.setStyle( mBorderStyle );
71  mPen.setWidthF( context.outputLineWidth( mBorderWidth ) );
72 }
73 
75 {
76 }
77 
78 void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
79 {
80  QPainter* p = context.renderContext().painter();
81  if ( !p )
82  {
83  return;
84  }
85 
86  p->setBrush( context.selected() ? mSelBrush : mBrush );
87  p->setPen( mPen );
88 
89  if ( !mOffset.isNull() )
90  p->translate( mOffset );
91 
92  _renderPolygon( p, points, rings );
93 
94  if ( !mOffset.isNull() )
95  p->translate( -mOffset );
96 }
97 
99 {
100  QgsStringMap map;
101  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
103  map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
104  map["style_border"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
105  map["width_border"] = QString::number( mBorderWidth );
106  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
107  return map;
108 }
109 
111 {
113  sl->setOffset( mOffset );
114  return sl;
115 }
116 
117 //QgsSVGFillSymbolLayer
118 
119 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): mPatternWidth( width ), mOutline( 0 )
120 {
121  setSvgFilePath( svgFilePath );
122  mOutlineWidth = 0.3;
123  mAngle = angle;
124  setSubSymbol( new QgsLineSymbolV2() );
125 }
126 
127 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): mPatternWidth( width ),
128  mSvgData( svgData ), mOutline( 0 )
129 {
130  storeViewBox();
131  mOutlineWidth = 0.3;
132  mAngle = angle;
133  setSubSymbol( new QgsLineSymbolV2() );
134 }
135 
137 {
138  delete mOutline;
139 }
140 
141 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
142 {
143  QFile svgFile( svgPath );
144  if ( svgFile.open( QFile::ReadOnly ) )
145  {
146  mSvgData = svgFile.readAll();
147  storeViewBox();
148  }
149  mSvgFilePath = svgPath;
150 }
151 
153 {
154  QByteArray data;
155  double width = 20;
156  QString svgFilePath;
157  double angle = 0.0;
158 
159 
160  if ( properties.contains( "width" ) )
161  {
162  width = properties["width"].toDouble();
163  }
164  if ( properties.contains( "svgFile" ) )
165  {
166  QString svgName = properties["svgFile"];
167  QString savePath = QgsSvgMarkerSymbolLayerV2::symbolNameToPath( svgName );
168  svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
169  }
170  if ( properties.contains( "angle" ) )
171  {
172  angle = properties["angle"].toDouble();
173  }
174 
175  if ( !svgFilePath.isEmpty() )
176  {
177  return new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
178  }
179  else
180  {
181  if ( properties.contains( "data" ) )
182  {
183  data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
184  }
185 
186  return new QgsSVGFillSymbolLayer( data, width, angle );
187  }
188 }
189 
191 {
192  return "SVGFill";
193 }
194 
196 {
197  if ( mSvgViewBox.isNull() )
198  {
199  return;
200  }
201 
202  //create QImage with appropriate dimensions
203  int pixelWidth = context.outputPixelSize( mPatternWidth );
204  int pixelHeight = pixelWidth / mSvgViewBox.width() * mSvgViewBox.height();
205 
206  QImage textureImage( pixelWidth, pixelHeight, QImage::Format_ARGB32_Premultiplied );
207  textureImage.fill( 0 ); // transparent background
208 
209  //rasterise byte array to image
210  QPainter p( &textureImage );
211  QSvgRenderer r( mSvgData );
212  if ( !r.isValid() )
213  {
214  return;
215  }
216 
217  r.render( &p );
218 
219  if ( context.alpha() < 1.0 )
220  {
221  QgsSymbolLayerV2Utils::multiplyImageOpacity( &textureImage, context.alpha() );
222  }
223 
224  QTransform brushTransform;
225  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
226  mBrush.setTextureImage( textureImage );
227  mBrush.setTransform( brushTransform );
228 
229  if ( mOutline )
230  {
231  mOutline->startRender( context.renderContext() );
232  }
233 }
234 
236 {
237  if ( mOutline )
238  {
239  mOutline->stopRender( context.renderContext() );
240  }
241 }
242 
243 void QgsSVGFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
244 {
245  QPainter* p = context.renderContext().painter();
246  if ( !p )
247  {
248  return;
249  }
250  p->setPen( QPen( Qt::NoPen ) );
251  if ( context.selected() )
252  {
253  QColor selColor = context.selectionColor();
254  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
255  p->setBrush( QBrush( selColor ) );
256  _renderPolygon( p, points, rings );
257  }
258 
259  if ( doubleNear( mAngle, 0.0 ) )
260  {
261  p->setBrush( mBrush );
262  }
263  else
264  {
265  QTransform t = mBrush.transform();
266  t.rotate( mAngle );
267  QBrush rotatedBrush = mBrush;
268  rotatedBrush.setTransform( t );
269  p->setBrush( rotatedBrush );
270  }
271  _renderPolygon( p, points, rings );
272  if ( mOutline )
273  {
274  mOutline->renderPolyline( points, context.renderContext(), -1, selectFillBorder && context.selected() );
275  if ( rings )
276  {
277  QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
278  for ( ; ringIt != rings->constEnd(); ++ringIt )
279  {
280  mOutline->renderPolyline( *ringIt, context.renderContext(), -1, selectFillBorder && context.selected() );
281  }
282  }
283  }
284 }
285 
287 {
288  QgsStringMap map;
289  if ( !mSvgFilePath.isEmpty() )
290  {
291  map.insert( "svgFile", QgsSvgMarkerSymbolLayerV2::symbolPathToName( mSvgFilePath ) );
292  }
293  else
294  {
295  map.insert( "data", QString( mSvgData.toHex() ) );
296  }
297 
298  map.insert( "width", QString::number( mPatternWidth ) );
299  map.insert( "angle", QString::number( mAngle ) );
300  return map;
301 }
302 
304 {
305  QgsSymbolLayerV2* clonedLayer = 0;
306  if ( !mSvgFilePath.isEmpty() )
307  {
309  }
310  else
311  {
312  clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
313  }
314 
315  if ( mOutline )
316  {
317  clonedLayer->setSubSymbol( mOutline->clone() );
318  }
319  return clonedLayer;
320 }
321 
323 {
324  if ( !mSvgData.isEmpty() )
325  {
326  QSvgRenderer r( mSvgData );
327  if ( r.isValid() )
328  {
329  mSvgViewBox = r.viewBoxF();
330  return;
331  }
332  }
333 
334  mSvgViewBox = QRectF();
335  return;
336 }
337 
339 {
340  if ( !symbol || symbol->type() != QgsSymbolV2::Line )
341  {
342  delete symbol;
343  return false;
344  }
345 
346  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
347  if ( lineSymbol )
348  {
349  delete mOutline;
350  mOutline = lineSymbol;
351  return true;
352  }
353 
354  delete symbol;
355  return false;
356 }
357 
358 
360 
361 
363 {
364  mMarker = NULL;
366 }
367 
369 {
370  delete mMarker;
371 }
372 
374 {
375  return new QgsCentroidFillSymbolLayerV2();
376 }
377 
379 {
380  return "CentroidFill";
381 }
382 
383 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
384 {
385  mMarker->setColor( color );
386  mColor = color;
387 }
388 
390 {
391  mMarker->setAlpha( context.alpha() );
392  mMarker->setOutputUnit( context.outputUnit() );
393 
394  mMarker->startRender( context.renderContext() );
395 }
396 
398 {
399  mMarker->stopRender( context.renderContext() );
400 }
401 
402 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
403 {
404  // calculate centroid
405  double cx = 0, cy = 0;
406  double area, sum = 0;
407  for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
408  {
409  const QPointF& p1 = points[i];
410  const QPointF& p2 = points[j];
411  area = p1.x() * p2.y() - p1.y() * p2.x();
412  sum += area;
413  cx += ( p1.x() + p2.x() ) * area;
414  cy += ( p1.y() + p2.y() ) * area;
415  }
416  sum *= 3.0;
417  cx /= sum;
418  cy /= sum;
419 
420  mMarker->renderPoint( QPointF( cx, cy ), context.renderContext(), -1, context.selected() );
421 }
422 
424 {
425  return QgsStringMap();
426 }
427 
429 {
431  x->setSubSymbol( mMarker->clone() );
432  return x;
433 }
434 
435 
437 {
438  return mMarker;
439 }
440 
442 {
443  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
444  {
445  delete symbol;
446  return false;
447  }
448 
449  delete mMarker;
450  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
451  mColor = mMarker->color();
452  return true;
453 }