QGIS API Documentation  2.11.0-Master
qgsmarkersymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmarkersymbollayerv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsmarkersymbollayerv2.h"
17 #include "qgssymbollayerv2utils.h"
18 
19 #include "qgsdxfexport.h"
20 #include "qgsdxfpaintdevice.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgslogger.h"
24 #include "qgssvgcache.h"
25 
26 #include <QPainter>
27 #include <QSvgRenderer>
28 #include <QFileInfo>
29 #include <QDir>
30 #include <QDomDocument>
31 #include <QDomElement>
32 
33 #include <cmath>
34 
35 Q_GUI_EXPORT extern int qt_defaultDpiX();
36 Q_GUI_EXPORT extern int qt_defaultDpiY();
37 
38 static void _fixQPictureDPI( QPainter* p )
39 {
40  // QPicture makes an assumption that we drawing to it with system DPI.
41  // Then when being drawn, it scales the painter. The following call
42  // negates the effect. There is no way of setting QPicture's DPI.
43  // See QTBUG-20361
44  p->scale(( double )qt_defaultDpiX() / p->device()->logicalDpiX(),
45  ( double )qt_defaultDpiY() / p->device()->logicalDpiY() );
46 }
47 
49 
51  : mOutlineStyle( Qt::SolidLine ), mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
52 {
53  mName = name;
54  mColor = color;
56  mSize = size;
57  mAngle = angle;
58  mOffset = QPointF( 0, 0 );
62  mUsingCache = false;
63 }
64 
66 {
73 
74  if ( props.contains( "name" ) )
75  name = props["name"];
76  if ( props.contains( "color" ) )
77  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
78  if ( props.contains( "color_border" ) )
79  {
80  //pre 2.5 projects use "color_border"
81  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
82  }
83  else if ( props.contains( "outline_color" ) )
84  {
85  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
86  }
87  else if ( props.contains( "line_color" ) )
88  {
89  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
90  }
91  if ( props.contains( "size" ) )
92  size = props["size"].toDouble();
93  if ( props.contains( "angle" ) )
94  angle = props["angle"].toDouble();
95  if ( props.contains( "scale_method" ) )
96  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
97 
98  QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod );
99  if ( props.contains( "offset" ) )
100  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
101  if ( props.contains( "offset_unit" ) )
102  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
103  if ( props.contains( "offset_map_unit_scale" ) )
104  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
105  if ( props.contains( "size_unit" ) )
106  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
107  if ( props.contains( "size_map_unit_scale" ) )
108  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
109 
110  if ( props.contains( "outline_style" ) )
111  {
112  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] ) );
113  }
114  else if ( props.contains( "line_style" ) )
115  {
116  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] ) );
117  }
118  if ( props.contains( "outline_width" ) )
119  {
120  m->setOutlineWidth( props["outline_width"].toDouble() );
121  }
122  else if ( props.contains( "line_width" ) )
123  {
124  m->setOutlineWidth( props["line_width"].toDouble() );
125  }
126  if ( props.contains( "outline_width_unit" ) )
127  {
128  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
129  }
130  if ( props.contains( "line_width_unit" ) )
131  {
132  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
133  }
134  if ( props.contains( "outline_width_map_unit_scale" ) )
135  {
136  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
137  }
138 
139  if ( props.contains( "horizontal_anchor_point" ) )
140  {
141  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
142  }
143  if ( props.contains( "vertical_anchor_point" ) )
144  {
145  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
146  }
147 
148  m->restoreDataDefinedProperties( props );
149 
150  return m;
151 }
152 
153 
155 {
156  return "SimpleMarker";
157 }
158 
160 {
161  QColor brushColor = mColor;
162  QColor penColor = mBorderColor;
163 
164  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
165  penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
166 
167  mBrush = QBrush( brushColor );
168  mPen = QPen( penColor );
171 
172  QColor selBrushColor = context.renderContext().selectionColor();
173  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
174  if ( context.alpha() < 1 )
175  {
176  selBrushColor.setAlphaF( context.alpha() );
177  selPenColor.setAlphaF( context.alpha() );
178  }
179  mSelBrush = QBrush( selBrushColor );
180  mSelPen = QPen( selPenColor );
183 
186 
187  // use caching only when:
188  // - size, rotation, shape, color, border color is not data-defined
189  // - drawing to screen (not printer)
190  mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
194 
195  // use either QPolygonF or QPainterPath for drawing
196  // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
197  if ( !prepareShape() ) // drawing as a polygon
198  {
199  if ( preparePath() ) // drawing as a painter path
200  {
201  // some markers can't be drawn as a polygon (circle, cross)
202  // For these set the selected border color to the selected color
203 
204  if ( mName != "circle" )
205  mSelPen.setColor( selBrushColor );
206  }
207  else
208  {
209  QgsDebugMsg( "unknown symbol" );
210  return;
211  }
212  }
213 
214  QMatrix transform;
215 
216  // scale the shape (if the size is not going to be modified)
217  if ( !hasDataDefinedSize )
218  {
220  if ( mUsingCache )
221  scaledSize *= context.renderContext().rasterScaleFactor();
222  double half = scaledSize / 2.0;
223  transform.scale( half, half );
224  }
225 
226  // rotate if the rotation is not going to be changed during the rendering
227  if ( !hasDataDefinedRotation && mAngle != 0 )
228  {
229  transform.rotate( mAngle );
230  }
231 
232  if ( !mPolygon.isEmpty() )
233  mPolygon = transform.map( mPolygon );
234  else
235  mPath = transform.map( mPath );
236 
237  if ( mUsingCache )
238  {
239  if ( !prepareCache( context ) )
240  {
241  mUsingCache = false;
242  }
243  }
244  else
245  {
246  mCache = QImage();
247  mSelCache = QImage();
248  }
249 
250  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
251 
253 }
254 
255 
257 {
259 
260  // calculate necessary image size for the cache
261  double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
262  int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
263  double center = imageSize / 2.0;
264 
265  if ( imageSize > mMaximumCacheWidth )
266  {
267  return false;
268  }
269 
270  mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
271  mCache.fill( 0 );
272 
273  QPainter p;
274  p.begin( &mCache );
275  p.setRenderHint( QPainter::Antialiasing );
276  p.setBrush( mBrush );
277  p.setPen( mPen );
278  p.translate( QPointF( center, center ) );
279  drawMarker( &p, context );
280  p.end();
281 
282  // Construct the selected version of the Cache
283 
284  QColor selColor = context.renderContext().selectionColor();
285 
286  mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
287  mSelCache.fill( 0 );
288 
289  p.begin( &mSelCache );
290  p.setRenderHint( QPainter::Antialiasing );
291  p.setBrush( mSelBrush );
292  p.setPen( mSelPen );
293  p.translate( QPointF( center, center ) );
294  drawMarker( &p, context );
295  p.end();
296 
297  // Check that the selected version is different. If not, then re-render,
298  // filling the background with the selection color and using the normal
299  // colors for the symbol .. could be ugly!
300 
301  if ( mSelCache == mCache )
302  {
303  p.begin( &mSelCache );
304  p.setRenderHint( QPainter::Antialiasing );
305  p.fillRect( 0, 0, imageSize, imageSize, selColor );
306  p.setBrush( mBrush );
307  p.setPen( mPen );
308  p.translate( QPointF( center, center ) );
309  drawMarker( &p, context );
310  p.end();
311  }
312 
313  return true;
314 }
315 
317 {
318  Q_UNUSED( context );
319 }
320 
322 {
323  mPolygon.clear();
324 
325  if ( name.isNull() )
326  {
327  name = mName;
328  }
329 
330  if ( name == "square" || name == "rectangle" )
331  {
332  mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
333  return true;
334  }
335  else if ( name == "diamond" )
336  {
337  mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
338  << QPointF( 1, 0 ) << QPointF( 0, -1 );
339  return true;
340  }
341  else if ( name == "pentagon" )
342  {
343  mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
344  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
345  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
346  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
347  << QPointF( 0, -1 );
348  return true;
349  }
350  else if ( name == "triangle" )
351  {
352  mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
353  return true;
354  }
355  else if ( name == "equilateral_triangle" )
356  {
357  mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
358  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
359  << QPointF( 0, -1 );
360  return true;
361  }
362  else if ( name == "star" )
363  {
364  double sixth = 1.0 / 3;
365 
366  mPolygon << QPointF( 0, -1 )
367  << QPointF( -sixth, -sixth )
368  << QPointF( -1, -sixth )
369  << QPointF( -sixth, 0 )
370  << QPointF( -1, 1 )
371  << QPointF( 0, + sixth )
372  << QPointF( 1, 1 )
373  << QPointF( + sixth, 0 )
374  << QPointF( 1, -sixth )
375  << QPointF( + sixth, -sixth );
376  return true;
377  }
378  else if ( name == "regular_star" )
379  {
380  double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
381 
382  mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
383  << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288 ) ) ) // 288
384  << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
385  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) ) // 216
386  << QPointF( 0, inner_r ) // 180
387  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) ) // 144
388  << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
389  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) ) // 72
390  << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
391  << QPointF( 0, -1 ); // 0
392  return true;
393  }
394  else if ( name == "arrow" )
395  {
396  mPolygon
397  << QPointF( 0, -1 )
398  << QPointF( 0.5, -0.5 )
399  << QPointF( 0.25, -0.5 )
400  << QPointF( 0.25, 1 )
401  << QPointF( -0.25, 1 )
402  << QPointF( -0.25, -0.5 )
403  << QPointF( -0.5, -0.5 );
404  return true;
405  }
406  else if ( name == "filled_arrowhead" )
407  {
408  mPolygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
409  return true;
410  }
411 
412  return false;
413 }
414 
416 {
417  mPath = QPainterPath();
418  if ( name.isNull() )
419  {
420  name = mName;
421  }
422 
423  if ( name == "circle" )
424  {
425  mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
426  return true;
427  }
428  else if ( name == "cross" )
429  {
430  mPath.moveTo( -1, 0 );
431  mPath.lineTo( 1, 0 ); // horizontal
432  mPath.moveTo( 0, -1 );
433  mPath.lineTo( 0, 1 ); // vertical
434  return true;
435  }
436  else if ( name == "x" || name == "cross2" )
437  {
438  mPath.moveTo( -1, -1 );
439  mPath.lineTo( 1, 1 );
440  mPath.moveTo( 1, -1 );
441  mPath.lineTo( -1, 1 );
442  return true;
443  }
444  else if ( name == "line" )
445  {
446  mPath.moveTo( 0, -1 );
447  mPath.lineTo( 0, 1 ); // vertical line
448  return true;
449  }
450  else if ( name == "arrowhead" )
451  {
452  mPath.moveTo( 0, 0 );
453  mPath.lineTo( -1, -1 );
454  mPath.moveTo( 0, 0 );
455  mPath.lineTo( -1, 1 );
456  return true;
457  }
458 
459  return false;
460 }
461 
463 {
464  QPainter *p = context.renderContext().painter();
465  if ( !p )
466  {
467  return;
468  }
469 
470  double scaledSize = mSize;
471 
473 
474  bool ok = true;
476  {
477  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context.feature(), mSize, &ok ).toDouble();
478  }
479 
480  if ( hasDataDefinedSize && ok )
481  {
482  switch ( mScaleMethod )
483  {
485  scaledSize = sqrt( scaledSize );
486  break;
488  break;
489  }
490  }
491 
492  //offset
493  double offsetX = 0;
494  double offsetY = 0;
495  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
496  QPointF off( offsetX, offsetY );
497 
498  //angle
499  double angle = mAngle + mLineAngle;
500  bool usingDataDefinedRotation = false;
502  {
503  angle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE, context.feature(), mAngle, &ok ).toDouble() + mLineAngle;
504  usingDataDefinedRotation = ok;
505  }
506 
507  bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
508  if ( hasDataDefinedRotation )
509  {
510  // For non-point markers, "dataDefinedRotation" means following the
511  // shape (shape-data defined). For them, "field-data defined" does
512  // not work at all. TODO: if "field-data defined" ever gets implemented
513  // we'll need a way to distinguish here between the two, possibly
514  // using another flag in renderHints()
515  const QgsFeature* f = context.feature();
516  if ( f )
517  {
518  const QgsGeometry *g = f->constGeometry();
519  if ( g && g->type() == QGis::Point )
520  {
521  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
522  angle += m2p.mapRotation();
523  }
524  }
525  }
526 
527  if ( angle )
528  off = _rotatedOffset( off, angle );
529 
530  //data defined shape?
531  bool createdNewPath = false;
533  {
535  if ( ok )
536  {
537  if ( !prepareShape( name ) ) // drawing as a polygon
538  {
539  preparePath( name ); // drawing as a painter path
540  }
541  createdNewPath = true;
542  }
543  }
544 
545  if ( mUsingCache )
546  {
547  //QgsDebugMsg( QString("XXX using cache") );
548  // we will use cached image
549  QImage &img = context.selected() ? mSelCache : mCache;
550  double s = img.width() / context.renderContext().rasterScaleFactor();
551  p->drawImage( QRectF( point.x() - s / 2.0 + off.x(),
552  point.y() - s / 2.0 + off.y(),
553  s, s ), img );
554  }
555  else
556  {
557  QMatrix transform;
558 
559  // move to the desired position
560  transform.translate( point.x() + off.x(), point.y() + off.y() );
561 
562  // resize if necessary
563  if ( hasDataDefinedSize || createdNewPath )
564  {
566  double half = s / 2.0;
567  transform.scale( half, half );
568  }
569 
570  if ( angle != 0 && ( hasDataDefinedRotation || createdNewPath ) )
571  transform.rotate( angle );
572 
574  {
575  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR, context.feature(), QVariant(), &ok ).toString();
576  if ( ok )
578  }
580  {
581  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR_BORDER, context.feature(), QVariant(), &ok ).toString();
582  if ( ok )
583  {
586  }
587  }
589  {
591  if ( ok )
592  {
595  }
596  }
598  {
600  if ( ok )
601  {
604  }
605  }
606 
607  p->setBrush( context.selected() ? mSelBrush : mBrush );
608  p->setPen( context.selected() ? mSelPen : mPen );
609 
610  if ( !mPolygon.isEmpty() )
611  p->drawPolygon( transform.map( mPolygon ) );
612  else
613  p->drawPath( transform.map( mPath ) );
614  }
615 }
616 
617 
619 {
620  QgsStringMap map;
621  map["name"] = mName;
622  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
623  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
624  map["size"] = QString::number( mSize );
626  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
627  map["angle"] = QString::number( mAngle );
628  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
630  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
632  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
633  map["outline_width"] = QString::number( mOutlineWidth );
634  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
635  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
636  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
637  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
638 
639 
640  //data define properties
642  return map;
643 }
644 
646 {
648  m->setOffset( mOffset );
649  m->setSizeUnit( mSizeUnit );
660  copyPaintEffect( m );
661  return m;
662 }
663 
665 {
666  // <Graphic>
667  QDomElement graphicElem = doc.createElement( "se:Graphic" );
668  element.appendChild( graphicElem );
669 
671 
672  // <Rotation>
673  QString angleFunc;
674  bool ok;
675  double angle = props.value( "angle", "0" ).toDouble( &ok );
676  if ( !ok )
677  {
678  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
679  }
680  else if ( angle + mAngle != 0 )
681  {
682  angleFunc = QString::number( angle + mAngle );
683  }
684  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
685 
686  // <Displacement>
688 }
689 
690 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
691 {
692  Q_UNUSED( mmScaleFactor );
693  Q_UNUSED( mapUnitScaleFactor );
694 #if 0
695  QString ogrType = "3"; //default is circle
696  if ( mName == "square" )
697  {
698  ogrType = "5";
699  }
700  else if ( mName == "triangle" )
701  {
702  ogrType = "7";
703  }
704  else if ( mName == "star" )
705  {
706  ogrType = "9";
707  }
708  else if ( mName == "circle" )
709  {
710  ogrType = "3";
711  }
712  else if ( mName == "cross" )
713  {
714  ogrType = "0";
715  }
716  else if ( mName == "x" || mName == "cross2" )
717  {
718  ogrType = "1";
719  }
720  else if ( mName == "line" )
721  {
722  ogrType = "10";
723  }
724 
725  QString ogrString;
726  ogrString.append( "SYMBOL(" );
727  ogrString.append( "id:" );
728  ogrString.append( "\"" );
729  ogrString.append( "ogr-sym-" );
730  ogrString.append( ogrType );
731  ogrString.append( "\"" );
732  ogrString.append( ",c:" );
733  ogrString.append( mColor.name() );
734  ogrString.append( ",o:" );
735  ogrString.append( mBorderColor.name() );
736  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
737  ogrString.append( ")" );
738  return ogrString;
739 #endif //0
740 
741  QString ogrString;
742  ogrString.append( "PEN(" );
743  ogrString.append( "c:" );
744  ogrString.append( mColor.name() );
745  ogrString.append( ",w:" );
746  ogrString.append( QString::number( mSize ) );
747  ogrString.append( "mm" );
748  ogrString.append( ")" );
749  return ogrString;
750 }
751 
753 {
754  QgsDebugMsg( "Entered." );
755 
756  QDomElement graphicElem = element.firstChildElement( "Graphic" );
757  if ( graphicElem.isNull() )
758  return NULL;
759 
760  QString name = "square";
762  double borderWidth, size;
763  Qt::PenStyle borderStyle;
764 
765  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
766  return NULL;
767 
768  double angle = 0.0;
769  QString angleFunc;
770  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
771  {
772  bool ok;
773  double d = angleFunc.toDouble( &ok );
774  if ( ok )
775  angle = d;
776  }
777 
778  QPointF offset;
780 
781  QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
782  m->setAngle( angle );
783  m->setOffset( offset );
784  m->setOutlineStyle( borderStyle );
785  return m;
786 }
787 
789 {
790  Q_UNUSED( context );
791 
792  if ( mPolygon.count() != 0 )
793  {
794  p->drawPolygon( mPolygon );
795  }
796  else
797  {
798  p->drawPath( mPath );
799  }
800 }
801 
802 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
803 {
804  //data defined size?
805  double size = mSize;
806 
807  bool hasDataDefinedSize = false;
808  if ( context )
809  {
811  }
812 
813  //data defined size
814  bool ok = true;
815  if ( hasDataDefinedSize )
816  {
818  {
820  }
821 
822  if ( ok )
823  {
824  switch ( mScaleMethod )
825  {
827  size = sqrt( size );
828  break;
830  break;
831  }
832  }
833 
835  }
836  if ( mSizeUnit == QgsSymbolV2::MM )
837  {
838  size *= mmMapUnitScaleFactor;
839  }
840  double halfSize = size / 2.0;
841 
842  //outlineWidth
843  double outlineWidth = mOutlineWidth;
844 
846  {
848  }
849  if ( mSizeUnit == QgsSymbolV2::MM )
850  {
851  outlineWidth *= mmMapUnitScaleFactor;
852  }
853 
854  //color
855  QColor pc = mPen.color();
856  QColor bc = mBrush.color();
858  {
860  if ( ok )
861  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
862  }
864  {
866  if ( ok )
867  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
868  }
869 
870  //offset
871  double offsetX = 0;
872  double offsetY = 0;
873  if ( context )
874  {
875  markerOffset( *context, offsetX, offsetY );
876  }
877  QPointF off( offsetX, offsetY );
878 
879  //angle
880  double angle = mAngle + mLineAngle;
882  {
884  }
885 
886  angle = -angle; //rotation in Qt is counterclockwise
887  if ( angle )
888  off = _rotatedOffset( off, angle );
889 
890  if ( mSizeUnit == QgsSymbolV2::MM )
891  {
892  off *= mmMapUnitScaleFactor;
893  }
894 
895  QTransform t;
896  t.translate( shift.x() + offsetX, shift.y() + offsetY );
897 
898  if ( angle != 0 )
899  t.rotate( angle );
900 
901  //data defined symbol name
902 
903  if ( mName == "circle" )
904  {
905  if ( mBrush.style() != Qt::NoBrush )
906  e.writeFilledCircle( layerName, bc, shift, halfSize );
907  if ( mPen.style() != Qt::NoPen )
908  e.writeCircle( layerName, pc, shift, halfSize, "CONTINUOUS", outlineWidth );
909  }
910  else if ( mName == "square" || mName == "rectangle" )
911  {
912  QgsPolygon p( 1 );
913  p[0].resize( 5 );
914  p[0][0] = t.map( QPointF( -halfSize, -halfSize ) );
915  p[0][1] = t.map( QPointF( -halfSize, halfSize ) );
916  p[0][2] = t.map( QPointF( halfSize, halfSize ) );
917  p[0][3] = t.map( QPointF( halfSize, -halfSize ) );
918  p[0][4] = p[0][0];
919 
920  if ( mBrush.style() != Qt::NoBrush )
921  e.writePolygon( p, layerName, "SOLID", bc );
922  if ( mPen.style() != Qt::NoPen )
923  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
924  }
925  else if ( mName == "diamond" )
926  {
927  QgsPolygon p( 1 );
928  p[0].resize( 5 );
929  p[0][0] = t.map( QPointF( -halfSize, 0 ) );
930  p[0][1] = t.map( QPointF( 0, halfSize ) );
931  p[0][3] = t.map( QPointF( halfSize, 0 ) );
932  p[0][1] = t.map( QPointF( 0, -halfSize ) );
933  p[0][4] = p[0][0];
934 
935  if ( mBrush.style() != Qt::NoBrush )
936  e.writePolygon( p, layerName, "SOLID", bc );
937  if ( mPen.style() != Qt::NoPen )
938  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
939  }
940  else if ( mName == "triangle" )
941  {
942  QgsPolygon p( 1 );
943  p[0].resize( 4 );
944  p[0][0] = t.map( QPointF( -halfSize, -halfSize ) );
945  p[0][1] = t.map( QPointF( halfSize, -halfSize ) );
946  p[0][1] = t.map( QPointF( 0, halfSize ) );
947  p[0][2] = p[0][0];
948 
949  if ( mBrush.style() != Qt::NoBrush )
950  e.writePolygon( p, layerName, "SOLID", bc );
951 
952  if ( mPen.style() != Qt::NoPen )
953  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
954  }
955 #if 0
956  else if ( mName == "equilateral_triangle" )
957  {
958 
959  }
960 #endif
961  else if ( mName == "line" )
962  {
963  QPointF pt1 = t.map( QPointF( 0, halfSize ) );
964  QPointF pt2 = t.map( QPointF( 0, -halfSize ) );
965 
966  if ( mPen.style() != Qt::NoPen )
967  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
968  }
969  else if ( mName == "cross" )
970  {
971  if ( mPen.style() != Qt::NoPen )
972  {
973  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
974  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
975  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
976  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
977 
978  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
979  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
980  }
981  }
982  else if ( mName == "x" || mName == "cross2" )
983  {
984  if ( mPen.style() != Qt::NoPen )
985  {
986  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
987  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
988  QPointF pt3 = t.map( QPointF( -halfSize, halfSize ) );
989  QPointF pt4 = t.map( QPointF( halfSize, -halfSize ) );
990 
991  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
992  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
993  }
994  }
995  else if ( mName == "arrowhead" )
996  {
997  if ( mPen.style() != Qt::NoPen )
998  {
999  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1000  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1001  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1002 
1003  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1004  e.writeLine( pt3, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1005  }
1006  }
1007  else if ( mName == "filled_arrowhead" )
1008  {
1009  if ( mBrush.style() != Qt::NoBrush )
1010  {
1011  QgsPolygon p( 1 );
1012  p[0].resize( 4 );
1013  p[0][0] = t.map( QPointF( -halfSize, halfSize ) );
1014  p[0][1] = t.map( QPointF( 0, 0 ) );
1015  p[0][2] = t.map( QPointF( -halfSize, -halfSize ) );
1016  p[0][3] = p[0][0];
1017  e.writePolygon( p, layerName, "SOLID", bc );
1018  }
1019  }
1020  else
1021  {
1022  return false;
1023  }
1024 
1025  return true;
1026 }
1027 
1028 
1030 {
1032  mOutlineWidthUnit = unit;
1033 }
1034 
1036 {
1038  {
1039  return mOutlineWidthUnit;
1040  }
1041  return QgsSymbolV2::Mixed;
1042 }
1043 
1045 {
1047  mOutlineWidthMapUnitScale = scale;
1048 }
1049 
1051 {
1053  {
1055  }
1056  return QgsMapUnitScale();
1057 }
1058 
1060 
1061 
1063 {
1065  mSize = size;
1066  mAngle = angle;
1067  mOffset = QPointF( 0, 0 );
1069  mOutlineWidth = 1.0;
1071  mFillColor = QColor( Qt::black );
1072  mOutlineColor = QColor( Qt::black );
1073 }
1074 
1075 
1077 {
1079  double size = DEFAULT_SVGMARKER_SIZE;
1080  double angle = DEFAULT_SVGMARKER_ANGLE;
1082 
1083  if ( props.contains( "name" ) )
1084  name = props["name"];
1085  if ( props.contains( "size" ) )
1086  size = props["size"].toDouble();
1087  if ( props.contains( "angle" ) )
1088  angle = props["angle"].toDouble();
1089  if ( props.contains( "scale_method" ) )
1090  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1091 
1092  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1093 
1094  //we only check the svg default parameters if necessary, since it could be expensive
1095  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1096  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1097  {
1099  double outlineWidth;
1100  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
1101  QgsSvgCache::instance()->containsParams( name, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
1102  if ( hasFillParam )
1103  {
1104  m->setFillColor( fillColor );
1105  }
1106  if ( hasOutlineParam )
1107  {
1108  m->setOutlineColor( outlineColor );
1109  }
1110  if ( hasOutlineWidthParam )
1111  {
1112  m->setOutlineWidth( outlineWidth );
1113  }
1114  }
1115 
1116  if ( props.contains( "size_unit" ) )
1117  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1118  if ( props.contains( "size_map_unit_scale" ) )
1119  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1120  if ( props.contains( "offset" ) )
1121  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1122  if ( props.contains( "offset_unit" ) )
1123  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1124  if ( props.contains( "offset_map_unit_scale" ) )
1125  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1126  if ( props.contains( "fill" ) )
1127  {
1128  //pre 2.5 projects used "fill"
1129  m->setFillColor( QColor( props["fill"] ) );
1130  }
1131  else if ( props.contains( "color" ) )
1132  {
1133  m->setFillColor( QColor( props["color"] ) );
1134  }
1135  if ( props.contains( "outline" ) )
1136  {
1137  //pre 2.5 projects used "outline"
1138  m->setOutlineColor( QColor( props["outline"] ) );
1139  }
1140  else if ( props.contains( "outline_color" ) )
1141  {
1142  m->setOutlineColor( QColor( props["outline_color"] ) );
1143  }
1144  else if ( props.contains( "line_color" ) )
1145  {
1146  m->setOutlineColor( QColor( props["line_color"] ) );
1147  }
1148 
1149  if ( props.contains( "outline-width" ) )
1150  {
1151  //pre 2.5 projects used "outline-width"
1152  m->setOutlineWidth( props["outline-width"].toDouble() );
1153  }
1154  else if ( props.contains( "outline_width" ) )
1155  {
1156  m->setOutlineWidth( props["outline_width"].toDouble() );
1157  }
1158  else if ( props.contains( "line_width" ) )
1159  {
1160  m->setOutlineWidth( props["line_width"].toDouble() );
1161  }
1162 
1163  if ( props.contains( "outline_width_unit" ) )
1164  {
1165  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1166  }
1167  else if ( props.contains( "line_width_unit" ) )
1168  {
1169  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1170  }
1171  if ( props.contains( "outline_width_map_unit_scale" ) )
1172  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1173 
1174  if ( props.contains( "horizontal_anchor_point" ) )
1175  {
1176  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1177  }
1178  if ( props.contains( "vertical_anchor_point" ) )
1179  {
1180  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1181  }
1182 
1183  m->restoreDataDefinedProperties( props );
1184 
1185  return m;
1186 }
1187 
1189 {
1190  mPath = path;
1192  double outlineWidth;
1193  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
1194  QgsSvgCache::instance()->containsParams( path, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
1195  if ( hasFillParam )
1196  {
1197  setFillColor( fillColor );
1198  }
1199  if ( hasOutlineParam )
1200  {
1201  setOutlineColor( outlineColor );
1202  }
1203  if ( hasOutlineWidthParam )
1204  {
1205  setOutlineWidth( outlineWidth );
1206  }
1207 }
1208 
1209 
1211 {
1212  return "SvgMarker";
1213 }
1214 
1216 {
1217  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1218  Q_UNUSED( context );
1219  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1220 }
1221 
1223 {
1224  Q_UNUSED( context );
1225 }
1226 
1228 {
1229  QPainter *p = context.renderContext().painter();
1230  if ( !p )
1231  return;
1232 
1233  double scaledSize = mSize;
1234 
1236 
1237  bool ok = true;
1239  {
1240  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context.feature(), mSize, &ok ).toDouble();
1241  }
1242 
1243  if ( hasDataDefinedSize && ok )
1244  {
1245  switch ( mScaleMethod )
1246  {
1248  scaledSize = sqrt( scaledSize );
1249  break;
1251  break;
1252  }
1253  }
1254 
1256 
1257  //don't render symbols with size below one or above 10,000 pixels
1258  if (( int )size < 1 || 10000.0 < size )
1259  {
1260  return;
1261  }
1262 
1263  p->save();
1264 
1265  //offset
1266  double offsetX = 0;
1267  double offsetY = 0;
1268  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1269  QPointF outputOffset( offsetX, offsetY );
1270 
1271  double angle = mAngle + mLineAngle;
1273  {
1275  }
1276 
1278  if ( hasDataDefinedRotation )
1279  {
1280  // For non-point markers, "dataDefinedRotation" means following the
1281  // shape (shape-data defined). For them, "field-data defined" does
1282  // not work at all. TODO: if "field-data defined" ever gets implemented
1283  // we'll need a way to distinguish here between the two, possibly
1284  // using another flag in renderHints()
1285  const QgsFeature* f = context.feature();
1286  if ( f )
1287  {
1288  const QgsGeometry *g = f->constGeometry();
1289  if ( g && g->type() == QGis::Point )
1290  {
1291  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1292  angle += m2p.mapRotation();
1293  }
1294  }
1295  }
1296 
1297  if ( angle )
1298  outputOffset = _rotatedOffset( outputOffset, angle );
1299  p->translate( point + outputOffset );
1300 
1301  bool rotated = !qgsDoubleNear( angle, 0 );
1302  if ( rotated )
1303  p->rotate( angle );
1304 
1305  QString path = mPath;
1307  {
1308  path = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_NAME, context.feature(), mPath ).toString();
1309  }
1310 
1311  double outlineWidth = mOutlineWidth;
1313  {
1315  }
1316 
1319  {
1320  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL, context.feature(), QVariant(), &ok ).toString();
1321  if ( ok )
1322  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1323  }
1324 
1327  {
1328  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE, context.feature(), QVariant(), &ok ).toString();
1329  if ( ok )
1330  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1331  }
1332 
1333  bool fitsInCache = true;
1334  bool usePict = true;
1335  double hwRatio = 1.0;
1336  if ( !context.renderContext().forceVectorOutput() && !rotated )
1337  {
1338  usePict = false;
1339  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1340  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1341  if ( fitsInCache && img.width() > 1 )
1342  {
1343  //consider transparency
1344  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1345  {
1346  QImage transparentImage = img.copy();
1347  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1348  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1349  hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width();
1350  }
1351  else
1352  {
1353  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1354  hwRatio = ( double )img.height() / ( double )img.width();
1355  }
1356  }
1357  }
1358 
1359  if ( usePict || !fitsInCache )
1360  {
1361  p->setOpacity( context.alpha() );
1362  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1364 
1365  if ( pct.width() > 1 )
1366  {
1367  p->save();
1368  _fixQPictureDPI( p );
1369  p->drawPicture( 0, 0, pct );
1370  p->restore();
1371  hwRatio = ( double )pct.height() / ( double )pct.width();
1372  }
1373  }
1374 
1375  if ( context.selected() )
1376  {
1377  QPen pen( context.renderContext().selectionColor() );
1379  if ( penWidth > size / 20 )
1380  {
1381  // keep the pen width from covering symbol
1382  penWidth = size / 20;
1383  }
1384  double penOffset = penWidth / 2;
1385  pen.setWidth( penWidth );
1386  p->setPen( pen );
1387  p->setBrush( Qt::NoBrush );
1388  double wSize = size + penOffset;
1389  double hSize = size * hwRatio + penOffset;
1390  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1391  }
1392 
1393  p->restore();
1394 }
1395 
1396 
1398 {
1399  QgsStringMap map;
1401  map["size"] = QString::number( mSize );
1402  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1403  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1404  map["angle"] = QString::number( mAngle );
1405  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1406  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1407  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1408  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1409  map["color"] = mFillColor.name();
1410  map["outline_color"] = mOutlineColor.name();
1411  map["outline_width"] = QString::number( mOutlineWidth );
1412  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1413  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1414  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1415  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1416 
1418  return map;
1419 }
1420 
1422 {
1424  m->setFillColor( mFillColor );
1429  m->setOffset( mOffset );
1430  m->setOffsetUnit( mOffsetUnit );
1432  m->setSizeUnit( mSizeUnit );
1437  copyPaintEffect( m );
1438  return m;
1439 }
1440 
1442 {
1444  mOutlineWidthUnit = unit;
1445 }
1446 
1448 {
1450  if ( unit != mOutlineWidthUnit )
1451  {
1452  return QgsSymbolV2::Mixed;
1453  }
1454  return unit;
1455 }
1456 
1458 {
1460  mOutlineWidthMapUnitScale = scale;
1461 }
1462 
1464 {
1466  {
1468  }
1469  return QgsMapUnitScale();
1470 }
1471 
1473 {
1474  // <Graphic>
1475  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1476  element.appendChild( graphicElem );
1477 
1478  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
1479 
1480  // <Rotation>
1481  QString angleFunc;
1482  bool ok;
1483  double angle = props.value( "angle", "0" ).toDouble( &ok );
1484  if ( !ok )
1485  {
1486  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1487  }
1488  else if ( angle + mAngle != 0 )
1489  {
1490  angleFunc = QString::number( angle + mAngle );
1491  }
1492 
1493  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1494 
1495  // <Displacement>
1497 }
1498 
1500 {
1501  QgsDebugMsg( "Entered." );
1502 
1503  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1504  if ( graphicElem.isNull() )
1505  return NULL;
1506 
1507  QString path, mimeType;
1508  QColor fillColor;
1509  double size;
1510 
1511  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1512  return NULL;
1513 
1514  if ( mimeType != "image/svg+xml" )
1515  return NULL;
1516 
1517  double angle = 0.0;
1518  QString angleFunc;
1519  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1520  {
1521  bool ok;
1522  double d = angleFunc.toDouble( &ok );
1523  if ( ok )
1524  angle = d;
1525  }
1526 
1527  QPointF offset;
1529 
1531  m->setFillColor( fillColor );
1532  //m->setOutlineColor( outlineColor );
1533  //m->setOutlineWidth( outlineWidth );
1534  m->setAngle( angle );
1535  m->setOffset( offset );
1536  return m;
1537 }
1538 
1539 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f,
1540  const QPointF& shift ) const
1541 {
1542  Q_UNUSED( layerName );
1543  Q_UNUSED( shift ); //todo...
1544 
1545  //size
1546  double size = mSize;
1547 
1549 
1550  bool ok = true;
1552  {
1554  }
1555 
1556  if ( hasDataDefinedSize && ok )
1557  {
1558  switch ( mScaleMethod )
1559  {
1561  size = sqrt( size );
1562  break;
1564  break;
1565  }
1566  }
1567 
1568  if ( mSizeUnit == QgsSymbolV2::MM )
1569  {
1570  size *= mmMapUnitScaleFactor;
1571  }
1572 
1573  double halfSize = size / 2.0;
1574 
1575  //offset, angle
1577 
1579  {
1581  if ( ok )
1582  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
1583  }
1584  double offsetX = offset.x();
1585  double offsetY = offset.y();
1586  if ( mSizeUnit == QgsSymbolV2::MM )
1587  {
1588  offsetX *= mmMapUnitScaleFactor;
1589  offsetY *= mmMapUnitScaleFactor;
1590  }
1591 
1592  QPointF outputOffset( offsetX, offsetY );
1593 
1594  double angle = mAngle + mLineAngle;
1596  {
1598  }
1599  //angle = -angle; //rotation in Qt is counterclockwise
1600  if ( angle )
1601  outputOffset = _rotatedOffset( outputOffset, angle );
1602 
1603  QString path = mPath;
1605  {
1607  }
1608 
1609  double outlineWidth = mOutlineWidth;
1611  {
1613  }
1614 
1617  {
1619  if ( ok )
1620  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1621  }
1622 
1625  {
1627  if ( ok )
1628  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1629  }
1630 
1631  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
1632  context->renderContext().scaleFactor(),
1633  context->renderContext().rasterScaleFactor() );
1634 
1635  //if current entry image is 0: cache image for entry
1636  // checks to see if image will fit into cache
1637  //update stats for memory usage
1638  QSvgRenderer r( svgContent );
1639  if ( !r.isValid() )
1640  {
1641  return false;
1642  }
1643 
1644  QgsDxfPaintDevice pd( &e );
1645  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
1646 
1647  QPainter p;
1648  p.begin( &pd );
1649  if ( !qgsDoubleNear( angle, 0.0 ) )
1650  {
1651  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
1652  p.rotate( angle );
1653  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
1654  }
1655  pd.setShift( shift );
1656  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
1657  pd.setLayer( layerName );
1658  r.render( &p );
1659  p.end();
1660  return true;
1661 }
1662 
1664 
1665 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
1666  : mFontMetrics( 0 )
1667 {
1669  mChr = chr;
1670  mColor = color;
1671  mAngle = angle;
1672  mSize = pointSize;
1673  mOrigSize = pointSize;
1675  mOffset = QPointF( 0, 0 );
1677 }
1678 
1680 {
1681  delete mFontMetrics;
1682 }
1683 
1685 {
1688  double pointSize = DEFAULT_FONTMARKER_SIZE;
1691 
1692  if ( props.contains( "font" ) )
1693  fontFamily = props["font"];
1694  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
1695  chr = props["chr"].at( 0 );
1696  if ( props.contains( "size" ) )
1697  pointSize = props["size"].toDouble();
1698  if ( props.contains( "color" ) )
1699  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
1700  if ( props.contains( "angle" ) )
1701  angle = props["angle"].toDouble();
1702 
1703  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
1704  if ( props.contains( "offset" ) )
1705  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1706  if ( props.contains( "offset_unit" ) )
1707  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
1708  if ( props.contains( "offset_map_unit_scale" ) )
1709  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
1710  if ( props.contains( "size_unit" ) )
1711  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1712  if ( props.contains( "size_map_unit_scale" ) )
1713  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1714  if ( props.contains( "horizontal_anchor_point" ) )
1715  {
1716  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1717  }
1718  if ( props.contains( "vertical_anchor_point" ) )
1719  {
1720  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1721  }
1722 
1723  m->restoreDataDefinedProperties( props );
1724 
1725  return m;
1726 }
1727 
1729 {
1730  return "FontMarker";
1731 }
1732 
1734 {
1735  mFont = QFont( mFontFamily );
1737  delete mFontMetrics;
1738  mFontMetrics = new QFontMetrics( mFont );
1739  mChrOffset = QPointF( mFontMetrics->width( mChr ) / 2.0, -mFontMetrics->ascent() / 2.0 );
1740  mOrigSize = mSize; // save in case the size would be data defined
1741  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1742 }
1743 
1745 {
1746  Q_UNUSED( context );
1747 }
1748 
1750 {
1751  QPainter *p = context.renderContext().painter();
1752  if ( !p )
1753  return;
1754 
1755  QColor penColor = mColor;
1756  bool ok;
1758  {
1759  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR, context.feature(), QVariant(), &ok ).toString();
1760  if ( ok )
1761  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1762  }
1763  penColor = context.selected() ? context.renderContext().selectionColor() : penColor;
1764  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
1765 
1766  p->setPen( penColor );
1767  p->setFont( mFont );
1768 
1769  p->save();
1770 
1771  QPointF chrOffset = mChrOffset;
1772  QString charToRender = mChr;
1774  {
1775  charToRender = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_CHAR, context.feature(), mChr ).toString();
1776  if ( charToRender != mChr )
1777  {
1778  chrOffset = QPointF( mFontMetrics->width( charToRender ) / 2.0, -mFontMetrics->ascent() / 2.0 );
1779  }
1780  }
1781 
1782  double scaledSize = mSize;
1783 
1785 
1786  ok = true;
1788  {
1789  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context.feature(), mSize, &ok ).toDouble();
1790  }
1791 
1792  if ( hasDataDefinedSize && ok )
1793  {
1794  switch ( mScaleMethod )
1795  {
1797  scaledSize = sqrt( scaledSize );
1798  break;
1800  break;
1801  }
1802  }
1803 
1804  //offset
1805  double offsetX = 0;
1806  double offsetY = 0;
1807  markerOffset( context, scaledSize, scaledSize , offsetX, offsetY );
1808  QPointF outputOffset( offsetX, offsetY );
1809 
1810  double angle = mAngle + mLineAngle;
1812  {
1814  }
1815 
1817  if ( hasDataDefinedRotation )
1818  {
1819  // For non-point markers, "dataDefinedRotation" means following the
1820  // shape (shape-data defined). For them, "field-data defined" does
1821  // not work at all. TODO: if "field-data defined" ever gets implemented
1822  // we'll need a way to distinguish here between the two, possibly
1823  // using another flag in renderHints()
1824  const QgsFeature* f = context.feature();
1825  if ( f )
1826  {
1827  const QgsGeometry *g = f->constGeometry();
1828  if ( g && g->type() == QGis::Point )
1829  {
1830  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1831  angle += m2p.mapRotation();
1832  }
1833  }
1834  }
1835 
1836  if ( angle )
1837  outputOffset = _rotatedOffset( outputOffset, angle );
1838  p->translate( point + outputOffset );
1839 
1840  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
1841  {
1842  double s = scaledSize / mOrigSize;
1843  p->scale( s, s );
1844  }
1845 
1846  bool rotated = !qgsDoubleNear( angle, 0 );
1847  if ( rotated )
1848  p->rotate( angle );
1849 
1850  p->drawText( -chrOffset, charToRender );
1851  p->restore();
1852 }
1853 
1855 {
1856  QgsStringMap props;
1857  props["font"] = mFontFamily;
1858  props["chr"] = mChr;
1859  props["size"] = QString::number( mSize );
1860  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1861  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1862  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1863  props["angle"] = QString::number( mAngle );
1864  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1865  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1866  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1867  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1868  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1869 
1870  //data define properties
1871  saveDataDefinedProperties( props );
1872 
1873  return props;
1874 }
1875 
1877 {
1879  m->setOffset( mOffset );
1880  m->setOffsetUnit( mOffsetUnit );
1882  m->setSizeUnit( mSizeUnit );
1887  copyPaintEffect( m );
1888  return m;
1889 }
1890 
1892 {
1893  // <Graphic>
1894  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1895  element.appendChild( graphicElem );
1896 
1897  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
1898  int markIndex = mChr.unicode();
1899  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
1900 
1901  // <Rotation>
1902  QString angleFunc;
1903  bool ok;
1904  double angle = props.value( "angle", "0" ).toDouble( &ok );
1905  if ( !ok )
1906  {
1907  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1908  }
1909  else if ( angle + mAngle != 0 )
1910  {
1911  angleFunc = QString::number( angle + mAngle );
1912  }
1913  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1914 
1915  // <Displacement>
1917 }
1918 
1920 {
1921  QgsDebugMsg( "Entered." );
1922 
1923  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1924  if ( graphicElem.isNull() )
1925  return NULL;
1926 
1927  QString name, format;
1928  QColor color;
1929  double size;
1930  int chr;
1931 
1932  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
1933  return NULL;
1934 
1935  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
1936  return NULL;
1937 
1938  QString fontFamily = name.mid( 6 );
1939 
1940  double angle = 0.0;
1941  QString angleFunc;
1942  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1943  {
1944  bool ok;
1945  double d = angleFunc.toDouble( &ok );
1946  if ( ok )
1947  angle = d;
1948  }
1949 
1950  QPointF offset;
1952 
1953  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
1954  m->setAngle( angle );
1955  m->setOffset( offset );
1956  return m;
1957 }
1958 
1959 
void addEllipse(const QRectF &boundingRectangle)
QgsSymbolV2::OutputUnit outputUnit() const override
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
Q_GUI_EXPORT int qt_defaultDpiX()
static const QString EXPR_CHAR
void setOutlineStyle(Qt::PenStyle outlineStyle)
void setOpacity(qreal opacity)
Qt::PenStyle style() const
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
void setStyle(Qt::PenStyle style)
QString & append(QChar ch)
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int ascent() const
int renderHints() const
Definition: qgssymbolv2.h:238
QgsMapUnitScale mSizeMapUnitScale
Q_GUI_EXPORT int qt_defaultDpiY()
int width() const
QString layerType() const override
bool end()
bool contains(const Key &key) const
QgsStringMap properties() const override
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
void fillRect(const QRectF &rectangle, const QBrush &brush)
qreal alphaF() const
A paint device for drawing into dxf files.
void setRenderHint(RenderHint hint, bool on)
QString layerType() const override
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_FONTMARKER_COLOR
void render(QPainter *painter)
QString name() const
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
Qt::BrushStyle style() const
QColor selectionColor() const
QgsSymbolLayerV2 * clone() const override
QgsSymbolV2::OutputUnit mOutlineWidthUnit
void setOutlineColor(const QColor &c) override
Set outline color.
QString layerType() const override
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QPoint map(const QPoint &point) const
#define DEFAULT_SIMPLEMARKER_ANGLE
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, QColor color)
Draw dxf polygon (HATCH)
static void createRotationElement(QDomDocument &doc, QDomElement &element, QString rotationFunc)
double rendererScale() const
void scale(qreal sx, qreal sy)
#define DEFAULT_FONTMARKER_CHR
bool isValid() const
void setOffset(QPointF offset)
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
#define DEG2RAD(x)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
#define DEFAULT_SIMPLEMARKER_COLOR
void save()
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
QgsSymbolLayerV2 * clone() const override
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
static QPointF decodePoint(QString str)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:75
void moveTo(const QPointF &point)
static QColor decodeColor(QString str)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
void stopRender(QgsSymbolV2RenderContext &context) override
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
double scaleFactor() const
QColor fillColor() const override
Get fill color.
void rotate(qreal angle)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:119
static void _fixQPictureDPI(QPainter *p)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QImage copy(const QRect &rectangle) const
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
double toDouble(bool *ok) const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
QgsSymbolLayerV2 * clone() const override
double mapRotation() const
Return current map rotation in degrees.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:350
static const QString EXPR_OFFSET
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
QSize defaultSize() const
void writeCircle(const QString &layer, QColor color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width)
Write circle (as polyline)
#define DEFAULT_SVGMARKER_ANGLE
static const QString EXPR_SIZE
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
bool isNull() const
static QString encodeColor(QColor color)
#define DEFAULT_SIMPLEMARKER_NAME
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:231
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
const QColor & color() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:96
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const override
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
QgsFontMarkerSymbolLayerV2(QString fontFamily=DEFAULT_FONTMARKER_FONT, QChar chr=DEFAULT_FONTMARKER_CHR, double pointSize=DEFAULT_FONTMARKER_SIZE, QColor color=DEFAULT_FONTMARKER_COLOR, double angle=DEFAULT_FONTMARKER_ANGLE)
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setPixelSize(int pixelSize)
static QString symbolPathToName(QString path)
Get symbols's name from its path.
QColor color() const
void clear()
void setFont(const QFont &font)
QTransform & translate(qreal dx, qreal dy)
void setMapUnitScale(const QgsMapUnitScale &scale) override
QString number(int n, int base)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit u)
qreal x() const
qreal y() const
void resize(int size)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:243
void fill(uint pixelValue)
static QString encodePoint(QPointF point)
QgsStringMap properties() const override
static Qt::PenStyle decodePenStyle(QString str)
void setPen(const QColor &color)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
int width() const
void lineTo(const QPointF &endPoint)
#define DEFAULT_SCALE_METHOD
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QMatrix & translate(qreal dx, qreal dy)
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsSymbolV2::ScaleMethod mScaleMethod
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
bool forceVectorOutput() const
void setLayer(const QString &layer)
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
QPaintDevice * device() const
QgsMapUnitScale mapUnitScale() const override
void setWidthF(qreal width)
QgsStringMap properties() const override
void stopRender(QgsSymbolV2RenderContext &context) override
void setBrush(const QBrush &brush)
void drawText(const QPointF &position, const QString &text)
double rasterScaleFactor() const
#define DEFAULT_FONTMARKER_ANGLE
QgsSymbolV2::OutputUnit outputUnit() const override
void writeLine(const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, QColor color, double width=-1)
Write line (as a polyline)
static const QString EXPR_FILL
virtual QColor color() const
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
QgsSvgMarkerSymbolLayerV2(QString name=DEFAULT_SVGMARKER_NAME, double size=DEFAULT_SVGMARKER_SIZE, double angle=DEFAULT_SVGMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
HorizontalAnchorPoint mHorizontalAnchorPoint
ushort unicode() const
void setColor(const QColor &color)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::ScaleMethod scaleMethod() const
static const QString EXPR_OUTLINE_STYLE
int logicalDpiX() const
int logicalDpiY() const
QgsSymbolV2::OutputUnit mOutlineWidthUnit
#define DEFAULT_SVGMARKER_SIZE
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
static const QString EXPR_COLOR
static const QString EXPR_ANGLE
int width(const QString &text, int len) const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const override
void startRender(QgsSymbolV2RenderContext &context) override
#define DEFAULT_FONTMARKER_SIZE
bool isNull() const
void restore()
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
#define DEFAULT_FONTMARKER_FONT
#define DEFAULT_SVGMARKER_NAME
QMatrix & rotate(qreal degrees)
#define DEFAULT_SIMPLEMARKER_SIZE
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
QString mid(int position, int n) const
void drawPath(const QPainterPath &path)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
virtual QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=0) const
Evaluates the matching data defined property and returns the calculated value.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QgsMapUnitScale mapUnitScale() const override
Qt::PenStyle outlineStyle() const
static const QString EXPR_NAME
void setShift(const QPointF &shift)
bool isEmpty() const
QgsSimpleMarkerSymbolLayerV2(QString name=DEFAULT_SIMPLEMARKER_NAME, QColor color=DEFAULT_SIMPLEMARKER_COLOR, QColor borderColor=DEFAULT_SIMPLEMARKER_BORDERCOLOR, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:221
QDomElement firstChildElement(const QString &tagName) const
bool preparePath(QString name=QString())
void writeFilledCircle(const QString &layer, QColor color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
int height() const
int count(const T &value) const
static const QString EXPR_COLOR_BORDER
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, QString path, QString mime, QColor color, double size=-1)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:68
qreal widthF() const
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const override
void translate(const QPointF &offset)
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, QString name, QColor color, QColor borderColor=QColor(), double borderWidth=-1, double size=-1)
const QgsMapToPixel & mapToPixel() const
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:249
QgsSymbolV2::OutputUnit mOffsetUnit
void setAlphaF(qreal alpha)
void startRender(QgsSymbolV2RenderContext &context) override
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
bool selected() const
Definition: qgssymbolv2.h:235
int height() const
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
double toDouble(bool *ok) const
void startRender(QgsSymbolV2RenderContext &context) override
VerticalAnchorPoint mVerticalAnchorPoint
bool prepareShape(QString name=QString())
QgsSymbolV2::OutputUnit mSizeUnit
void setDrawingSize(const QSizeF &size)
QgsMapUnitScale mOffsetMapUnitScale
void drawPicture(const QPointF &point, const QPicture &picture)
static const QString EXPR_OUTLINE
void markerOffset(const QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
int height() const
QDomElement createElement(const QString &tagName)
void map(int x, int y, int *tx, int *ty) const
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, QColor color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
void setAngle(double angle)
bool begin(QPaintDevice *device)
QPointF offset() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setColor(const QColor &color)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
QColor outlineColor() const override
Get outline color.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, QString path, QString format, int *markIndex=0, QColor color=QColor(), double size=-1)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
QMatrix & scale(qreal sx, qreal sy)
void setFillColor(const QColor &c) override
Set fill color.
void setOutputSize(const QRectF &r)
const T value(const Key &key) const
static QPointF _rotatedOffset(const QPointF &offset, double angle)
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR