QGIS API Documentation  2.14.11-Essen
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 #include "qgsunittypes.h"
26 
27 #include <QPainter>
28 #include <QSvgRenderer>
29 #include <QFileInfo>
30 #include <QDir>
31 #include <QDomDocument>
32 #include <QDomElement>
33 
34 #include <cmath>
35 
36 Q_GUI_EXPORT extern int qt_defaultDpiX();
37 Q_GUI_EXPORT extern int qt_defaultDpiY();
38 
39 static void _fixQPictureDPI( QPainter* p )
40 {
41  // QPicture makes an assumption that we drawing to it with system DPI.
42  // Then when being drawn, it scales the painter. The following call
43  // negates the effect. There is no way of setting QPicture's DPI.
44  // See QTBUG-20361
45  p->scale( static_cast< double >( qt_defaultDpiX() ) / p->device()->logicalDpiX(),
46  static_cast< double >( qt_defaultDpiY() ) / p->device()->logicalDpiY() );
47 }
48 
50 
51 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( const QString& name, const QColor& color, const QColor& borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod )
52  : mOutlineStyle( Qt::SolidLine ), mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
53 {
54  mName = name;
55  mColor = color;
57  mSize = size;
58  mAngle = angle;
59  mOffset = QPointF( 0, 0 );
63  mUsingCache = false;
64 }
65 
67 {
74 
75  if ( props.contains( "name" ) )
76  name = props["name"];
77  if ( props.contains( "color" ) )
78  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
79  if ( props.contains( "color_border" ) )
80  {
81  //pre 2.5 projects use "color_border"
82  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
83  }
84  else if ( props.contains( "outline_color" ) )
85  {
86  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
87  }
88  else if ( props.contains( "line_color" ) )
89  {
90  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
91  }
92  if ( props.contains( "size" ) )
93  size = props["size"].toDouble();
94  if ( props.contains( "angle" ) )
95  angle = props["angle"].toDouble();
96  if ( props.contains( "scale_method" ) )
97  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
98 
99  QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod );
100  if ( props.contains( "offset" ) )
101  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
102  if ( props.contains( "offset_unit" ) )
103  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
104  if ( props.contains( "offset_map_unit_scale" ) )
105  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
106  if ( props.contains( "size_unit" ) )
107  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
108  if ( props.contains( "size_map_unit_scale" ) )
109  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
110 
111  if ( props.contains( "outline_style" ) )
112  {
113  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] ) );
114  }
115  else if ( props.contains( "line_style" ) )
116  {
117  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] ) );
118  }
119  if ( props.contains( "outline_width" ) )
120  {
121  m->setOutlineWidth( props["outline_width"].toDouble() );
122  }
123  else if ( props.contains( "line_width" ) )
124  {
125  m->setOutlineWidth( props["line_width"].toDouble() );
126  }
127  if ( props.contains( "outline_width_unit" ) )
128  {
129  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
130  }
131  if ( props.contains( "line_width_unit" ) )
132  {
133  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
134  }
135  if ( props.contains( "outline_width_map_unit_scale" ) )
136  {
137  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
138  }
139 
140  if ( props.contains( "horizontal_anchor_point" ) )
141  {
142  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
143  }
144  if ( props.contains( "vertical_anchor_point" ) )
145  {
146  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
147  }
148 
149  m->restoreDataDefinedProperties( props );
150 
151  return m;
152 }
153 
154 
156 {
157  return "SimpleMarker";
158 }
159 
161 {
162  QColor brushColor = mColor;
163  QColor penColor = mBorderColor;
164 
165  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
166  penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
167 
168  mBrush = QBrush( brushColor );
169  mPen = QPen( penColor );
172 
173  QColor selBrushColor = context.renderContext().selectionColor();
174  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
175  if ( context.alpha() < 1 )
176  {
177  selBrushColor.setAlphaF( context.alpha() );
178  selPenColor.setAlphaF( context.alpha() );
179  }
180  mSelBrush = QBrush( selBrushColor );
181  mSelPen = QPen( selPenColor );
184 
187 
188  // use caching only when:
189  // - size, rotation, shape, color, border color is not data-defined
190  // - drawing to screen (not printer)
191  mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
195 
196  // use either QPolygonF or QPainterPath for drawing
197  // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
198  if ( !prepareShape() ) // drawing as a polygon
199  {
200  if ( preparePath() ) // drawing as a painter path
201  {
202  // some markers can't be drawn as a polygon (circle, cross)
203  // For these set the selected border color to the selected color
204 
205  if ( mName != "circle" )
206  mSelPen.setColor( selBrushColor );
207  }
208  else
209  {
210  QgsDebugMsg( "unknown symbol" );
211  return;
212  }
213  }
214 
215  QMatrix transform;
216 
217  // scale the shape (if the size is not going to be modified)
218  if ( !hasDataDefinedSize )
219  {
221  if ( mUsingCache )
222  scaledSize *= context.renderContext().rasterScaleFactor();
223  double half = scaledSize / 2.0;
224  transform.scale( half, half );
225  }
226 
227  // rotate if the rotation is not going to be changed during the rendering
228  if ( !hasDataDefinedRotation && !qgsDoubleNear( mAngle, 0.0 ) )
229  {
230  transform.rotate( mAngle );
231  }
232 
233  if ( !mPolygon.isEmpty() )
234  mPolygon = transform.map( mPolygon );
235  else
236  mPath = transform.map( mPath );
237 
238  if ( mUsingCache )
239  {
240  if ( !prepareCache( context ) )
241  {
242  mUsingCache = false;
243  }
244  }
245  else
246  {
247  mCache = QImage();
248  mSelCache = QImage();
249  }
250 
251  prepareExpressions( context );
252 
254 }
255 
256 
258 {
260 
261  // calculate necessary image size for the cache
262  double pw = (( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
263  int imageSize = ( static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
264  double center = imageSize / 2.0;
265 
266  if ( imageSize > mMaximumCacheWidth )
267  {
268  return false;
269  }
270 
271  mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
272  mCache.fill( 0 );
273 
274  QPainter p;
275  p.begin( &mCache );
276  p.setRenderHint( QPainter::Antialiasing );
277  p.setBrush( mBrush );
278  p.setPen( mPen );
279  p.translate( QPointF( center, center ) );
280  drawMarker( &p, context );
281  p.end();
282 
283  // Construct the selected version of the Cache
284 
285  QColor selColor = context.renderContext().selectionColor();
286 
287  mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
288  mSelCache.fill( 0 );
289 
290  p.begin( &mSelCache );
291  p.setRenderHint( QPainter::Antialiasing );
292  p.setBrush( mSelBrush );
293  p.setPen( mSelPen );
294  p.translate( QPointF( center, center ) );
295  drawMarker( &p, context );
296  p.end();
297 
298  // Check that the selected version is different. If not, then re-render,
299  // filling the background with the selection color and using the normal
300  // colors for the symbol .. could be ugly!
301 
302  if ( mSelCache == mCache )
303  {
304  p.begin( &mSelCache );
305  p.setRenderHint( QPainter::Antialiasing );
306  p.fillRect( 0, 0, imageSize, imageSize, selColor );
307  p.setBrush( mBrush );
308  p.setPen( mPen );
309  p.translate( QPointF( center, center ) );
310  drawMarker( &p, context );
311  p.end();
312  }
313 
314  return true;
315 }
316 
318 {
319  Q_UNUSED( context );
320 }
321 
323 {
324  return prepareShape( name.isNull() ? mName : name, mPolygon );
325 }
326 
328 {
329  polygon.clear();
330 
331  if ( name == "square" || name == "rectangle" )
332  {
333  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
334  return true;
335  }
336  else if ( name == "diamond" )
337  {
338  polygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
339  << QPointF( 1, 0 ) << QPointF( 0, -1 );
340  return true;
341  }
342  else if ( name == "pentagon" )
343  {
344  polygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
345  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
346  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
347  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
348  << QPointF( 0, -1 );
349  return true;
350  }
351  else if ( name == "triangle" )
352  {
353  polygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
354  return true;
355  }
356  else if ( name == "equilateral_triangle" )
357  {
358  polygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
359  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
360  << QPointF( 0, -1 );
361  return true;
362  }
363  else if ( name == "star" )
364  {
365  double sixth = 1.0 / 3;
366 
367  polygon << QPointF( 0, -1 )
368  << QPointF( -sixth, -sixth )
369  << QPointF( -1, -sixth )
370  << QPointF( -sixth, 0 )
371  << QPointF( -1, 1 )
372  << QPointF( 0, + sixth )
373  << QPointF( 1, 1 )
374  << QPointF( + sixth, 0 )
375  << QPointF( 1, -sixth )
376  << QPointF( + sixth, -sixth );
377  return true;
378  }
379  else if ( name == "regular_star" )
380  {
381  double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
382 
383  polygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
384  << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288 ) ) ) // 288
385  << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
386  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) ) // 216
387  << QPointF( 0, inner_r ) // 180
388  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) ) // 144
389  << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
390  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) ) // 72
391  << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
392  << QPointF( 0, -1 ); // 0
393  return true;
394  }
395  else if ( name == "arrow" )
396  {
397  polygon << 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  polygon << 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  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
465  //of the rendered point!
466 
467  QPainter *p = context.renderContext().painter();
468  if ( !p )
469  {
470  return;
471  }
472 
473  bool hasDataDefinedSize = false;
474  double scaledSize = calculateSize( context, hasDataDefinedSize );
475 
476  bool hasDataDefinedRotation = false;
477  QPointF offset;
478  double angle = 0;
479  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
480 
481  //data defined shape?
482  bool createdNewPath = false;
483  bool ok = true;
485  {
486  context.setOriginalValueVariable( mName );
488  if ( ok )
489  {
490  if ( !prepareShape( name ) ) // drawing as a polygon
491  {
492  preparePath( name ); // drawing as a painter path
493  }
494  createdNewPath = true;
495  }
496  }
497 
498  if ( mUsingCache )
499  {
500  //QgsDebugMsg( QString("XXX using cache") );
501  // we will use cached image
502  QImage &img = context.selected() ? mSelCache : mCache;
503  double s = img.width() / context.renderContext().rasterScaleFactor();
504  p->drawImage( QRectF( point.x() - s / 2.0 + offset.x(),
505  point.y() - s / 2.0 + offset.y(),
506  s, s ), img );
507  }
508  else
509  {
510  QMatrix transform;
511 
512  // move to the desired position
513  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
514 
515  // resize if necessary
516  if ( hasDataDefinedSize || createdNewPath )
517  {
519  double half = s / 2.0;
520  transform.scale( half, half );
521  }
522 
523  if ( !qgsDoubleNear( angle, 0.0 ) && ( hasDataDefinedRotation || createdNewPath ) )
524  transform.rotate( angle );
525 
527  {
530  if ( ok )
532  }
534  {
537  if ( ok )
538  {
541  }
542  }
544  {
547  if ( ok )
548  {
551  }
552  }
554  {
557  if ( ok )
558  {
561  }
562  }
563 
564  p->setBrush( context.selected() ? mSelBrush : mBrush );
565  p->setPen( context.selected() ? mSelPen : mPen );
566 
567  if ( !mPolygon.isEmpty() )
568  p->drawPolygon( transform.map( mPolygon ) );
569  else
570  p->drawPath( transform.map( mPath ) );
571  }
572 }
573 
574 
575 double QgsSimpleMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
576 {
577  double scaledSize = mSize;
578 
580  bool ok = true;
582  {
583  context.setOriginalValueVariable( mSize );
585  }
586 
587  if ( hasDataDefinedSize && ok )
588  {
589  switch ( mScaleMethod )
590  {
592  scaledSize = sqrt( scaledSize );
593  break;
595  break;
596  }
597  }
598 
599  return scaledSize;
600 }
601 
602 void QgsSimpleMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
603  double scaledSize,
604  bool& hasDataDefinedRotation,
605  QPointF& offset,
606  double& angle ) const
607 {
608  //offset
609  double offsetX = 0;
610  double offsetY = 0;
611  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
612  offset = QPointF( offsetX, offsetY );
613 
614  //angle
615  bool ok = true;
616  angle = mAngle + mLineAngle;
617  bool usingDataDefinedRotation = false;
619  {
620  context.setOriginalValueVariable( angle );
622  usingDataDefinedRotation = ok;
623  }
624 
625  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
626  if ( hasDataDefinedRotation )
627  {
628  // For non-point markers, "dataDefinedRotation" means following the
629  // shape (shape-data defined). For them, "field-data defined" does
630  // not work at all. TODO: if "field-data defined" ever gets implemented
631  // we'll need a way to distinguish here between the two, possibly
632  // using another flag in renderHints()
633  const QgsFeature* f = context.feature();
634  if ( f )
635  {
636  const QgsGeometry *g = f->constGeometry();
637  if ( g && g->type() == QGis::Point )
638  {
639  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
640  angle += m2p.mapRotation();
641  }
642  }
643  }
644 
645  if ( angle )
646  offset = _rotatedOffset( offset, angle );
647 }
648 
650 {
651  QgsStringMap map;
652  map["name"] = mName;
653  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
654  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
655  map["size"] = QString::number( mSize );
657  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
658  map["angle"] = QString::number( mAngle );
659  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
661  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
663  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
664  map["outline_width"] = QString::number( mOutlineWidth );
665  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
666  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
667  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
668  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
669 
670 
671  //data define properties
673  return map;
674 }
675 
677 {
679  m->setOffset( mOffset );
680  m->setSizeUnit( mSizeUnit );
691  copyPaintEffect( m );
692  return m;
693 }
694 
696 {
697  // <Graphic>
698  QDomElement graphicElem = doc.createElement( "se:Graphic" );
699  element.appendChild( graphicElem );
700 
703  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mName, mColor, mBorderColor, mOutlineStyle, outlineWidth, size );
704 
705  // <Rotation>
706  QString angleFunc;
707  bool ok;
708  double angle = props.value( "angle", "0" ).toDouble( &ok );
709  if ( !ok )
710  {
711  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
712  }
713  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
714  {
715  angleFunc = QString::number( angle + mAngle );
716  }
717  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
718 
719  // <Displacement>
721  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
722 }
723 
724 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
725 {
726  Q_UNUSED( mmScaleFactor );
727  Q_UNUSED( mapUnitScaleFactor );
728 #if 0
729  QString ogrType = "3"; //default is circle
730  if ( mName == "square" )
731  {
732  ogrType = "5";
733  }
734  else if ( mName == "triangle" )
735  {
736  ogrType = "7";
737  }
738  else if ( mName == "star" )
739  {
740  ogrType = "9";
741  }
742  else if ( mName == "circle" )
743  {
744  ogrType = "3";
745  }
746  else if ( mName == "cross" )
747  {
748  ogrType = "0";
749  }
750  else if ( mName == "x" || mName == "cross2" )
751  {
752  ogrType = "1";
753  }
754  else if ( mName == "line" )
755  {
756  ogrType = "10";
757  }
758 
759  QString ogrString;
760  ogrString.append( "SYMBOL(" );
761  ogrString.append( "id:" );
762  ogrString.append( '\"' );
763  ogrString.append( "ogr-sym-" );
764  ogrString.append( ogrType );
765  ogrString.append( '\"' );
766  ogrString.append( ",c:" );
767  ogrString.append( mColor.name() );
768  ogrString.append( ",o:" );
769  ogrString.append( mBorderColor.name() );
770  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
771  ogrString.append( ')' );
772  return ogrString;
773 #endif //0
774 
775  QString ogrString;
776  ogrString.append( "PEN(" );
777  ogrString.append( "c:" );
778  ogrString.append( mColor.name() );
779  ogrString.append( ",w:" );
780  ogrString.append( QString::number( mSize ) );
781  ogrString.append( "mm" );
782  ogrString.append( ")" );
783  return ogrString;
784 }
785 
787 {
788  QgsDebugMsg( "Entered." );
789 
790  QDomElement graphicElem = element.firstChildElement( "Graphic" );
791  if ( graphicElem.isNull() )
792  return nullptr;
793 
794  QString name = "square";
796  double borderWidth, size;
797  Qt::PenStyle borderStyle;
798 
799  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
800  return nullptr;
801 
802  double angle = 0.0;
803  QString angleFunc;
804  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
805  {
806  bool ok;
807  double d = angleFunc.toDouble( &ok );
808  if ( ok )
809  angle = d;
810  }
811 
812  QPointF offset;
814 
815  QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
816  m->setAngle( angle );
817  m->setOffset( offset );
818  m->setOutlineStyle( borderStyle );
819  return m;
820 }
821 
823 {
824  Q_UNUSED( context );
825 
826  if ( mPolygon.count() != 0 )
827  {
828  p->drawPolygon( mPolygon );
829  }
830  else
831  {
832  p->drawPath( mPath );
833  }
834 }
835 
836 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
837 {
838  //data defined size?
839  double size = mSize;
840 
842 
843  //data defined size
844  bool ok = true;
845  if ( hasDataDefinedSize )
846  {
848  {
849  context.setOriginalValueVariable( mSize );
851  }
852 
853  if ( ok )
854  {
855  switch ( mScaleMethod )
856  {
858  size = sqrt( size );
859  break;
861  break;
862  }
863  }
864 
866  }
867  if ( mSizeUnit == QgsSymbolV2::MM )
868  {
869  size *= mmMapUnitScaleFactor;
870  }
871  double halfSize = size / 2.0;
872 
873  //outlineWidth
874  double outlineWidth = mOutlineWidth;
875 
877  {
880  }
881  if ( mSizeUnit == QgsSymbolV2::MM )
882  {
883  outlineWidth *= mmMapUnitScaleFactor;
884  }
885 
886  //color
887  QColor pc = mPen.color();
888  QColor bc = mBrush.color();
890  {
893  if ( ok )
894  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
895  }
897  {
900  if ( ok )
901  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
902  }
903 
904  //offset
905  double offsetX = 0;
906  double offsetY = 0;
907  markerOffset( context, offsetX, offsetY );
908 
909  QPointF off( offsetX, offsetY );
910 
911  //angle
912  double angle = mAngle + mLineAngle;
914  {
915  context.setOriginalValueVariable( mAngle );
917  }
918 
919  QString name( mName );
921  {
922  context.setOriginalValueVariable( mName );
924  }
925 
926  angle = -angle; //rotation in Qt is counterclockwise
927  if ( angle )
928  off = _rotatedOffset( off, angle );
929 
930  if ( mSizeUnit == QgsSymbolV2::MM )
931  {
932  off *= mmMapUnitScaleFactor;
933  }
934 
935  QTransform t;
936  t.translate( shift.x() + offsetX, shift.y() + offsetY );
937 
938  if ( !qgsDoubleNear( angle, 0.0 ) )
939  t.rotate( angle );
940 
941  QPolygonF polygon;
942  if ( prepareShape( name, polygon ) )
943  {
944  t.scale( halfSize, -halfSize );
945 
946  polygon = t.map( polygon );
947 
948  QgsPolygon p( 1 );
949  p.resize( 1 );
950  p[0].resize( polygon.size() + 1 );
951  int i = 0;
952  for ( i = 0; i < polygon.size(); i++ )
953  p[0][i] = polygon[i];
954  p[0][i] = p[0][0];
955 
956  if ( mBrush.style() != Qt::NoBrush )
957  e.writePolygon( p, layerName, "SOLID", bc );
958  if ( mPen.style() != Qt::NoPen )
959  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
960  }
961  else if ( name == "circle" )
962  {
963  if ( mBrush.style() != Qt::NoBrush )
964  e.writeFilledCircle( layerName, bc, shift, halfSize );
965  if ( mPen.style() != Qt::NoPen )
966  e.writeCircle( layerName, pc, shift, halfSize, "CONTINUOUS", outlineWidth );
967  }
968  else if ( name == "line" )
969  {
970  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
971  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
972 
973  if ( mPen.style() != Qt::NoPen )
974  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
975  }
976  else if ( name == "cross" )
977  {
978  if ( mPen.style() != Qt::NoPen )
979  {
980  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
981  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
982  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
983  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
984 
985  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
986  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
987  }
988  }
989  else if ( name == "x" || name == "cross2" )
990  {
991  if ( mPen.style() != Qt::NoPen )
992  {
993  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
994  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
995  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
996  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
997 
998  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
999  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
1000  }
1001  }
1002  else if ( name == "arrowhead" )
1003  {
1004  if ( mPen.style() != Qt::NoPen )
1005  {
1006  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1007  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1008  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1009 
1010  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1011  e.writeLine( pt3, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1012  }
1013  }
1014  else
1015  {
1016  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( name ) );
1017  return false;
1018  }
1019 
1020  return true;
1021 }
1022 
1023 
1025 {
1027  mOutlineWidthUnit = unit;
1028 }
1029 
1031 {
1033  {
1034  return mOutlineWidthUnit;
1035  }
1036  return QgsSymbolV2::Mixed;
1037 }
1038 
1040 {
1042  mOutlineWidthMapUnitScale = scale;
1043 }
1044 
1046 {
1048  {
1050  }
1051  return QgsMapUnitScale();
1052 }
1053 
1055 {
1056  bool hasDataDefinedSize = false;
1057  double scaledSize = calculateSize( context, hasDataDefinedSize );
1058 
1059  bool hasDataDefinedRotation = false;
1060  QPointF offset;
1061  double angle = 0;
1062  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
1063 
1065  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1066 
1067  QMatrix transform;
1068 
1069  // move to the desired position
1070  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
1071 
1072  if ( !qgsDoubleNear( angle, 0.0 ) )
1073  transform.rotate( angle );
1074 
1075  double penWidth = 0.0;
1076  bool ok = true;
1078  {
1081  if ( ok )
1082  {
1084  }
1085  }
1087  {
1090  if ( ok && outlineStyle == "no" )
1091  {
1092  penWidth = 0.0;
1093  }
1094  }
1095  //antialiasing
1096  penWidth += pixelSize;
1097 
1098  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1099  -scaledSize / 2.0,
1100  scaledSize,
1101  scaledSize ) );
1102 
1103  //extend bounds by pen width / 2.0
1104  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1105  penWidth / 2.0, penWidth / 2.0 );
1106 
1107  return symbolBounds;
1108 }
1109 
1111 
1112 
1114 {
1116  mSize = size;
1117  mAngle = angle;
1118  mOffset = QPointF( 0, 0 );
1120  mOutlineWidth = 0.2;
1122  mColor = QColor( Qt::black );
1123  mOutlineColor = QColor( Qt::black );
1124 }
1125 
1126 
1128 {
1130  double size = DEFAULT_SVGMARKER_SIZE;
1131  double angle = DEFAULT_SVGMARKER_ANGLE;
1133 
1134  if ( props.contains( "name" ) )
1135  name = props["name"];
1136  if ( props.contains( "size" ) )
1137  size = props["size"].toDouble();
1138  if ( props.contains( "angle" ) )
1139  angle = props["angle"].toDouble();
1140  if ( props.contains( "scale_method" ) )
1141  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1142 
1143  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1144 
1145  //we only check the svg default parameters if necessary, since it could be expensive
1146  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1147  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1148  {
1150  double fillOpacity = 1.0;
1151  double outlineOpacity = 1.0;
1152  double outlineWidth;
1153  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1154  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1155  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1156  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1157  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1158  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1159  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1160  if ( hasDefaultFillColor )
1161  {
1162  m->setFillColor( fillColor );
1163  }
1164  if ( hasDefaultFillOpacity )
1165  {
1166  QColor c = m->fillColor();
1167  c.setAlphaF( fillOpacity );
1168  m->setFillColor( c );
1169  }
1170  if ( hasDefaultOutlineColor )
1171  {
1172  m->setOutlineColor( outlineColor );
1173  }
1174  if ( hasDefaultOutlineWidth )
1175  {
1176  m->setOutlineWidth( outlineWidth );
1177  }
1178  if ( hasDefaultOutlineOpacity )
1179  {
1180  QColor c = m->outlineColor();
1181  c.setAlphaF( outlineOpacity );
1182  m->setOutlineColor( c );
1183  }
1184  }
1185 
1186  if ( props.contains( "size_unit" ) )
1187  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1188  if ( props.contains( "size_map_unit_scale" ) )
1189  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1190  if ( props.contains( "offset" ) )
1191  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1192  if ( props.contains( "offset_unit" ) )
1193  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1194  if ( props.contains( "offset_map_unit_scale" ) )
1195  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1196  if ( props.contains( "fill" ) )
1197  {
1198  //pre 2.5 projects used "fill"
1199  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1200  }
1201  else if ( props.contains( "color" ) )
1202  {
1203  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1204  }
1205  if ( props.contains( "outline" ) )
1206  {
1207  //pre 2.5 projects used "outline"
1208  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1209  }
1210  else if ( props.contains( "outline_color" ) )
1211  {
1212  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1213  }
1214  else if ( props.contains( "line_color" ) )
1215  {
1216  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1217  }
1218 
1219  if ( props.contains( "outline-width" ) )
1220  {
1221  //pre 2.5 projects used "outline-width"
1222  m->setOutlineWidth( props["outline-width"].toDouble() );
1223  }
1224  else if ( props.contains( "outline_width" ) )
1225  {
1226  m->setOutlineWidth( props["outline_width"].toDouble() );
1227  }
1228  else if ( props.contains( "line_width" ) )
1229  {
1230  m->setOutlineWidth( props["line_width"].toDouble() );
1231  }
1232 
1233  if ( props.contains( "outline_width_unit" ) )
1234  {
1235  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1236  }
1237  else if ( props.contains( "line_width_unit" ) )
1238  {
1239  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1240  }
1241  if ( props.contains( "outline_width_map_unit_scale" ) )
1242  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1243 
1244  if ( props.contains( "horizontal_anchor_point" ) )
1245  {
1246  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1247  }
1248  if ( props.contains( "vertical_anchor_point" ) )
1249  {
1250  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1251  }
1252 
1253  m->restoreDataDefinedProperties( props );
1254 
1255  return m;
1256 }
1257 
1259 {
1260  mPath = path;
1261  QColor defaultFillColor, defaultOutlineColor;
1262  double outlineWidth, fillOpacity, outlineOpacity;
1263  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1264  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1265  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1266  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1267  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1268  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1269  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1270 
1271  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1272  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1273 
1274  if ( hasDefaultFillColor )
1275  {
1276  defaultFillColor.setAlphaF( newFillOpacity );
1277  setFillColor( defaultFillColor );
1278  }
1279  if ( hasDefaultFillOpacity )
1280  {
1281  QColor c = fillColor();
1282  c.setAlphaF( fillOpacity );
1283  setFillColor( c );
1284  }
1285  if ( hasDefaultOutlineColor )
1286  {
1287  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1288  setOutlineColor( defaultOutlineColor );
1289  }
1290  if ( hasDefaultOutlineWidth )
1291  {
1292  setOutlineWidth( outlineWidth );
1293  }
1294  if ( hasDefaultOutlineOpacity )
1295  {
1296  QColor c = outlineColor();
1297  c.setAlphaF( outlineOpacity );
1298  setOutlineColor( c );
1299  }
1300 }
1301 
1302 
1304 {
1305  return "SvgMarker";
1306 }
1307 
1309 {
1310  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1311  Q_UNUSED( context );
1312  prepareExpressions( context );
1313 }
1314 
1316 {
1317  Q_UNUSED( context );
1318 }
1319 
1321 {
1322  QPainter *p = context.renderContext().painter();
1323  if ( !p )
1324  return;
1325 
1326  bool hasDataDefinedSize = false;
1327  double scaledSize = calculateSize( context, hasDataDefinedSize );
1329 
1330  //don't render symbols with size below one or above 10,000 pixels
1331  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1332  {
1333  return;
1334  }
1335 
1336  p->save();
1337 
1338  QPointF outputOffset;
1339  double angle = 0.0;
1340  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1341 
1342  p->translate( point + outputOffset );
1343 
1344  bool rotated = !qgsDoubleNear( angle, 0 );
1345  if ( rotated )
1346  p->rotate( angle );
1347 
1348  QString path = mPath;
1350  {
1351  context.setOriginalValueVariable( mPath );
1353  }
1354 
1355  double outlineWidth = mOutlineWidth;
1357  {
1360  }
1362 
1364  bool ok = false;
1366  {
1369  if ( ok )
1370  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1371  }
1372 
1373  QColor outlineColor = mOutlineColor;
1375  {
1378  if ( ok )
1379  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1380  }
1381 
1382  bool fitsInCache = true;
1383  bool usePict = true;
1384  double hwRatio = 1.0;
1385  if ( !context.renderContext().forceVectorOutput() && !rotated )
1386  {
1387  usePict = false;
1388  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1389  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1390  if ( fitsInCache && img.width() > 1 )
1391  {
1392  //consider transparency
1393  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1394  {
1395  QImage transparentImage = img.copy();
1396  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1397  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1398  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
1399  }
1400  else
1401  {
1402  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1403  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
1404  }
1405  }
1406  }
1407 
1408  if ( usePict || !fitsInCache )
1409  {
1410  p->setOpacity( context.alpha() );
1411  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1413 
1414  if ( pct.width() > 1 )
1415  {
1416  p->save();
1417  _fixQPictureDPI( p );
1418  p->drawPicture( 0, 0, pct );
1419  p->restore();
1420  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
1421  }
1422  }
1423 
1424  if ( context.selected() )
1425  {
1426  QPen pen( context.renderContext().selectionColor() );
1428  if ( penWidth > size / 20 )
1429  {
1430  // keep the pen width from covering symbol
1431  penWidth = size / 20;
1432  }
1433  double penOffset = penWidth / 2;
1434  pen.setWidth( penWidth );
1435  p->setPen( pen );
1436  p->setBrush( Qt::NoBrush );
1437  double wSize = size + penOffset;
1438  double hSize = size * hwRatio + penOffset;
1439  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1440  }
1441 
1442  p->restore();
1443 
1445  {
1446  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
1447  p->setRenderHint( QPainter::Antialiasing );
1448  }
1449 
1450 }
1451 
1452 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
1453 {
1454  double scaledSize = mSize;
1456 
1457  bool ok = true;
1459  {
1460  context.setOriginalValueVariable( mSize );
1461  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
1462  }
1463 
1464  if ( hasDataDefinedSize && ok )
1465  {
1466  switch ( mScaleMethod )
1467  {
1469  scaledSize = sqrt( scaledSize );
1470  break;
1472  break;
1473  }
1474  }
1475 
1476  return scaledSize;
1477 }
1478 
1479 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
1480 {
1481  //offset
1482  double offsetX = 0;
1483  double offsetY = 0;
1484  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1485  offset = QPointF( offsetX, offsetY );
1486 
1487  angle = mAngle + mLineAngle;
1489  {
1490  context.setOriginalValueVariable( mAngle );
1492  }
1493 
1495  if ( hasDataDefinedRotation )
1496  {
1497  // For non-point markers, "dataDefinedRotation" means following the
1498  // shape (shape-data defined). For them, "field-data defined" does
1499  // not work at all. TODO: if "field-data defined" ever gets implemented
1500  // we'll need a way to distinguish here between the two, possibly
1501  // using another flag in renderHints()
1502  const QgsFeature* f = context.feature();
1503  if ( f )
1504  {
1505  const QgsGeometry *g = f->constGeometry();
1506  if ( g && g->type() == QGis::Point )
1507  {
1508  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1509  angle += m2p.mapRotation();
1510  }
1511  }
1512  }
1513 
1514  if ( angle )
1515  offset = _rotatedOffset( offset, angle );
1516 }
1517 
1518 
1520 {
1521  QgsStringMap map;
1523  map["size"] = QString::number( mSize );
1524  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1525  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1526  map["angle"] = QString::number( mAngle );
1527  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1528  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1529  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1530  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1531  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1532  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
1533  map["outline_width"] = QString::number( mOutlineWidth );
1534  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1535  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1536  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1537  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1538 
1540  return map;
1541 }
1542 
1544 {
1546  m->setColor( mColor );
1547  m->setOutlineColor( mOutlineColor );
1551  m->setOffset( mOffset );
1552  m->setOffsetUnit( mOffsetUnit );
1554  m->setSizeUnit( mSizeUnit );
1559  copyPaintEffect( m );
1560  return m;
1561 }
1562 
1564 {
1566  mOutlineWidthUnit = unit;
1567 }
1568 
1570 {
1572  if ( unit != mOutlineWidthUnit )
1573  {
1574  return QgsSymbolV2::Mixed;
1575  }
1576  return unit;
1577 }
1578 
1580 {
1582  mOutlineWidthMapUnitScale = scale;
1583 }
1584 
1586 {
1588  {
1590  }
1591  return QgsMapUnitScale();
1592 }
1593 
1595 {
1596  // <Graphic>
1597  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1598  element.appendChild( graphicElem );
1599 
1601  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, size );
1602 
1603  // <Rotation>
1604  QString angleFunc;
1605  bool ok;
1606  double angle = props.value( "angle", "0" ).toDouble( &ok );
1607  if ( !ok )
1608  {
1609  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1610  }
1611  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1612  {
1613  angleFunc = QString::number( angle + mAngle );
1614  }
1615 
1616  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1617 
1618  // <Displacement>
1620  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
1621 }
1622 
1624 {
1625  QgsDebugMsg( "Entered." );
1626 
1627  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1628  if ( graphicElem.isNull() )
1629  return nullptr;
1630 
1631  QString path, mimeType;
1632  QColor fillColor;
1633  double size;
1634 
1635  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1636  return nullptr;
1637 
1638  if ( mimeType != "image/svg+xml" )
1639  return nullptr;
1640 
1641  double angle = 0.0;
1642  QString angleFunc;
1643  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1644  {
1645  bool ok;
1646  double d = angleFunc.toDouble( &ok );
1647  if ( ok )
1648  angle = d;
1649  }
1650 
1651  QPointF offset;
1653 
1655  m->setFillColor( fillColor );
1656  //m->setOutlineColor( outlineColor );
1657  //m->setOutlineWidth( outlineWidth );
1658  m->setAngle( angle );
1659  m->setOffset( offset );
1660  return m;
1661 }
1662 
1663 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
1664 {
1665  Q_UNUSED( layerName );
1666  Q_UNUSED( shift ); //todo...
1667 
1668  //size
1669  double size = mSize;
1670 
1672 
1673  bool ok = true;
1675  {
1676  context.setOriginalValueVariable( mSize );
1678  }
1679 
1680  if ( hasDataDefinedSize && ok )
1681  {
1682  switch ( mScaleMethod )
1683  {
1685  size = sqrt( size );
1686  break;
1688  break;
1689  }
1690  }
1691 
1692  if ( mSizeUnit == QgsSymbolV2::MM )
1693  {
1694  size *= mmMapUnitScaleFactor;
1695  }
1696 
1697  double halfSize = size / 2.0;
1698 
1699  //offset, angle
1700  QPointF offset = mOffset;
1701 
1703  {
1706  if ( ok )
1707  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
1708  }
1709  double offsetX = offset.x();
1710  double offsetY = offset.y();
1711  if ( mSizeUnit == QgsSymbolV2::MM )
1712  {
1713  offsetX *= mmMapUnitScaleFactor;
1714  offsetY *= mmMapUnitScaleFactor;
1715  }
1716 
1717  QPointF outputOffset( offsetX, offsetY );
1718 
1719  double angle = mAngle + mLineAngle;
1721  {
1722  context.setOriginalValueVariable( mAngle );
1724  }
1725  //angle = -angle; //rotation in Qt is counterclockwise
1726  if ( angle )
1727  outputOffset = _rotatedOffset( outputOffset, angle );
1728 
1729  QString path = mPath;
1731  {
1732  context.setOriginalValueVariable( mPath );
1734  }
1735 
1736  double outlineWidth = mOutlineWidth;
1738  {
1741  }
1743 
1746  {
1749  if ( ok )
1750  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1751  }
1752 
1753  QColor outlineColor = mOutlineColor;
1755  {
1758  if ( ok )
1759  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1760  }
1761 
1762  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
1763  context.renderContext().scaleFactor(),
1764  context.renderContext().rasterScaleFactor() );
1765 
1766  //if current entry image is 0: cache image for entry
1767  // checks to see if image will fit into cache
1768  //update stats for memory usage
1769  QSvgRenderer r( svgContent );
1770  if ( !r.isValid() )
1771  {
1772  return false;
1773  }
1774 
1775  QgsDxfPaintDevice pd( &e );
1776  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
1777 
1778  QPainter p;
1779  p.begin( &pd );
1780  if ( !qgsDoubleNear( angle, 0.0 ) )
1781  {
1782  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
1783  p.rotate( angle );
1784  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
1785  }
1786  pd.setShift( shift );
1787  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
1788  pd.setLayer( layerName );
1789  r.render( &p );
1790  p.end();
1791  return true;
1792 }
1793 
1795 {
1796  bool hasDataDefinedSize = false;
1797  double scaledSize = calculateSize( context, hasDataDefinedSize );
1799 
1800  //don't render symbols with size below one or above 10,000 pixels
1801  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
1802  {
1803  return QRectF();
1804  }
1805 
1806  QPointF outputOffset;
1807  double angle = 0.0;
1808  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1809 
1810  QString path = mPath;
1812  {
1813  context.setOriginalValueVariable( mPath );
1815  }
1816 
1817  double outlineWidth = mOutlineWidth;
1819  {
1822  }
1824 
1825  //need to get colors to take advantage of cached SVGs
1827  bool ok = false;
1829  {
1832  if ( ok )
1833  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1834  }
1835 
1836  QColor outlineColor = mOutlineColor;
1838  {
1841  if ( ok )
1842  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1843  }
1844 
1845  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
1846  context.renderContext().scaleFactor(),
1847  context.renderContext().rasterScaleFactor() );
1848 
1849  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
1850  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1851 
1852  QMatrix transform;
1853 
1854  // move to the desired position
1855  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
1856 
1857  if ( !qgsDoubleNear( angle, 0.0 ) )
1858  transform.rotate( angle );
1859 
1860  //antialiasing
1861  outlineWidth += pixelSize / 2.0;
1862 
1863  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1864  -scaledHeight / 2.0,
1865  scaledSize,
1866  scaledHeight ) );
1867 
1868  //extend bounds by pen width / 2.0
1869  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
1870  outlineWidth / 2.0, outlineWidth / 2.0 );
1871 
1872  return symbolBounds;
1873 
1874 }
1875 
1877 
1878 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
1879  : mFontMetrics( nullptr )
1880  , mChrWidth( 0 )
1881 {
1883  mChr = chr;
1884  mColor = color;
1885  mAngle = angle;
1886  mSize = pointSize;
1887  mOrigSize = pointSize;
1889  mOffset = QPointF( 0, 0 );
1891 }
1892 
1894 {
1895  delete mFontMetrics;
1896 }
1897 
1899 {
1902  double pointSize = DEFAULT_FONTMARKER_SIZE;
1905 
1906  if ( props.contains( "font" ) )
1907  fontFamily = props["font"];
1908  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
1909  chr = props["chr"].at( 0 );
1910  if ( props.contains( "size" ) )
1911  pointSize = props["size"].toDouble();
1912  if ( props.contains( "color" ) )
1913  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
1914  if ( props.contains( "angle" ) )
1915  angle = props["angle"].toDouble();
1916 
1917  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
1918  if ( props.contains( "offset" ) )
1919  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1920  if ( props.contains( "offset_unit" ) )
1921  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
1922  if ( props.contains( "offset_map_unit_scale" ) )
1923  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
1924  if ( props.contains( "size_unit" ) )
1925  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1926  if ( props.contains( "size_map_unit_scale" ) )
1927  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1928  if ( props.contains( "horizontal_anchor_point" ) )
1929  {
1930  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1931  }
1932  if ( props.contains( "vertical_anchor_point" ) )
1933  {
1934  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1935  }
1936 
1937  m->restoreDataDefinedProperties( props );
1938 
1939  return m;
1940 }
1941 
1943 {
1944  return "FontMarker";
1945 }
1946 
1948 {
1949  mFont = QFont( mFontFamily );
1951  delete mFontMetrics;
1952  mFontMetrics = new QFontMetrics( mFont );
1954  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
1955  mOrigSize = mSize; // save in case the size would be data defined
1956  prepareExpressions( context );
1957 }
1958 
1960 {
1961  Q_UNUSED( context );
1962 }
1963 
1964 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
1965 {
1966  charOffset = mChrOffset;
1967  QString charToRender = mChr;
1969  {
1970  context.setOriginalValueVariable( mChr );
1972  if ( charToRender != mChr )
1973  {
1974  charWidth = mFontMetrics->width( charToRender );
1975  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
1976  }
1977  }
1978  return charToRender;
1979 }
1980 
1981 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
1982  double scaledSize,
1983  bool& hasDataDefinedRotation,
1984  QPointF& offset,
1985  double& angle ) const
1986 {
1987  //offset
1988  double offsetX = 0;
1989  double offsetY = 0;
1990  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1991  offset = QPointF( offsetX, offsetY );
1992 
1993  //angle
1994  bool ok = true;
1995  angle = mAngle + mLineAngle;
1996  bool usingDataDefinedRotation = false;
1998  {
1999  context.setOriginalValueVariable( angle );
2001  usingDataDefinedRotation = ok;
2002  }
2003 
2004  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2005  if ( hasDataDefinedRotation )
2006  {
2007  // For non-point markers, "dataDefinedRotation" means following the
2008  // shape (shape-data defined). For them, "field-data defined" does
2009  // not work at all. TODO: if "field-data defined" ever gets implemented
2010  // we'll need a way to distinguish here between the two, possibly
2011  // using another flag in renderHints()
2012  const QgsFeature* f = context.feature();
2013  if ( f )
2014  {
2015  const QgsGeometry *g = f->constGeometry();
2016  if ( g && g->type() == QGis::Point )
2017  {
2018  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2019  angle += m2p.mapRotation();
2020  }
2021  }
2022  }
2023 
2024  if ( angle )
2025  offset = _rotatedOffset( offset, angle );
2026 }
2027 
2028 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2029 {
2030  double scaledSize = mSize;
2032 
2033  bool ok = true;
2035  {
2036  context.setOriginalValueVariable( mSize );
2037  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2038  }
2039 
2040  if ( hasDataDefinedSize && ok )
2041  {
2042  switch ( mScaleMethod )
2043  {
2045  scaledSize = sqrt( scaledSize );
2046  break;
2048  break;
2049  }
2050  }
2051  return scaledSize;
2052 }
2053 
2055 {
2056  QPainter *p = context.renderContext().painter();
2057  if ( !p )
2058  return;
2059 
2060  QColor penColor = mColor;
2061  bool ok;
2063  {
2066  if ( ok )
2067  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2068  }
2069  penColor = context.selected() ? context.renderContext().selectionColor() : penColor;
2070  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2071 
2072  p->setPen( penColor );
2073  p->setFont( mFont );
2074  p->save();
2075 
2076  QPointF chrOffset = mChrOffset;
2077  double chrWidth;
2078  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2079 
2080  double sizeToRender = calculateSize( context );
2081 
2082  bool hasDataDefinedRotation = false;
2083  QPointF offset;
2084  double angle = 0;
2085  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2086 
2087  p->translate( point + offset );
2088 
2089  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2090  {
2091  double s = sizeToRender / mOrigSize;
2092  p->scale( s, s );
2093  }
2094 
2095  if ( !qgsDoubleNear( angle, 0 ) )
2096  p->rotate( angle );
2097 
2098  p->drawText( -chrOffset, charToRender );
2099  p->restore();
2100 }
2101 
2103 {
2104  QgsStringMap props;
2105  props["font"] = mFontFamily;
2106  props["chr"] = mChr;
2107  props["size"] = QString::number( mSize );
2108  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2109  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2110  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2111  props["angle"] = QString::number( mAngle );
2112  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2113  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2114  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2115  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2116  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2117 
2118  //data define properties
2119  saveDataDefinedProperties( props );
2120 
2121  return props;
2122 }
2123 
2125 {
2127  m->setOffset( mOffset );
2128  m->setOffsetUnit( mOffsetUnit );
2130  m->setSizeUnit( mSizeUnit );
2135  copyPaintEffect( m );
2136  return m;
2137 }
2138 
2140 {
2141  // <Graphic>
2142  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2143  element.appendChild( graphicElem );
2144 
2145  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2146  int markIndex = mChr.unicode();
2148  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, size );
2149 
2150  // <Rotation>
2151  QString angleFunc;
2152  bool ok;
2153  double angle = props.value( "angle", "0" ).toDouble( &ok );
2154  if ( !ok )
2155  {
2156  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2157  }
2158  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2159  {
2160  angleFunc = QString::number( angle + mAngle );
2161  }
2162  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2163 
2164  // <Displacement>
2166  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
2167 }
2168 
2170 {
2171  QPointF chrOffset = mChrOffset;
2172  double chrWidth = mChrWidth;
2173  //calculate width of rendered character
2174  ( void )characterToRender( context, chrOffset, chrWidth );
2175 
2176  if ( !mFontMetrics )
2177  mFontMetrics = new QFontMetrics( mFont );
2178 
2179  double scaledSize = calculateSize( context );
2180  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2181  {
2182  chrWidth *= scaledSize / mOrigSize;
2183  }
2184 
2185  bool hasDataDefinedRotation = false;
2186  QPointF offset;
2187  double angle = 0;
2188  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2190 
2191  QMatrix transform;
2192 
2193  // move to the desired position
2194  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2195 
2196  if ( !qgsDoubleNear( angle, 0.0 ) )
2197  transform.rotate( angle );
2198 
2199  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2200  -scaledSize / 2.0,
2201  chrWidth,
2202  scaledSize ) );
2203  return symbolBounds;
2204 }
2205 
2207 {
2208  QgsDebugMsg( "Entered." );
2209 
2210  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2211  if ( graphicElem.isNull() )
2212  return nullptr;
2213 
2214  QString name, format;
2215  QColor color;
2216  double size;
2217  int chr;
2218 
2219  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2220  return nullptr;
2221 
2222  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2223  return nullptr;
2224 
2225  QString fontFamily = name.mid( 6 );
2226 
2227  double angle = 0.0;
2228  QString angleFunc;
2229  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2230  {
2231  bool ok;
2232  double d = angleFunc.toDouble( &ok );
2233  if ( ok )
2234  angle = d;
2235  }
2236 
2237  QPointF offset;
2239 
2240  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2241  m->setAngle( angle );
2242  m->setOffset( offset );
2243  return m;
2244 }
2245 
2246 
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)
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
void setOpacity(qreal opacity)
Qt::PenStyle style() const
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
void setStyle(Qt::PenStyle style)
QString & append(QChar ch)
static QPointF _rotatedOffset(QPointF offset, double angle)
QgsSimpleMarkerSymbolLayerV2(const QString &name=DEFAULT_SIMPLEMARKER_NAME, const QColor &color=DEFAULT_SIMPLEMARKER_COLOR, const QColor &borderColor=DEFAULT_SIMPLEMARKER_BORDERCOLOR, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int ascent() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
void writeLine(const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Write line (as a polyline)
QgsMapUnitScale mSizeMapUnitScale
Q_GUI_EXPORT int qt_defaultDpiY()
int width() const
QString layerType() const override
Returns a string that represents this layer type.
bool end()
bool contains(const Key &key) const
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
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
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
A paint device for drawing into dxf files.
void setRenderHint(RenderHint hint, bool on)
QString layerType() const override
Returns a string that represents this layer type.
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_FONTMARKER_COLOR
void render(QPainter *painter)
static double rescaleUom(double size, QgsSymbolV2::OutputUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found, otherwise returns the value un-modified.
Use antialiasing while drawing.
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&.
QSizeF svgViewboxSize(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Calculates the viewbox size of a (possibly cached) SVG file.
Qt::BrushStyle style() const
void setOutlineColor(const QColor &c) override
Set outline color.
QString layerType() const override
Returns a string that represents this layer type.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QPoint map(const QPoint &point) const
static QString encodeColor(const QColor &color)
#define DEFAULT_SIMPLEMARKER_ANGLE
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
void scale(qreal sx, qreal sy)
void setDrawingSize(QSizeF size)
#define DEFAULT_FONTMARKER_CHR
static QgsSymbolV2::ScaleMethod decodeScaleMethod(const QString &str)
Calculate scale by the diameter.
Definition: qgssymbolv2.h:90
bool isValid() const
void setOffset(QPointF offset)
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
bool isValid() const
#define DEG2RAD(x)
#define DEFAULT_SIMPLEMARKER_COLOR
void save()
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
void setFillColor(const QColor &color) override
Set fill color.
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:76
void moveTo(const QPointF &point)
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
static QPointF decodePoint(const QString &str)
Flags flags() const
Return combination of flags used for rendering.
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.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
void stopRender(QgsSymbolV2RenderContext &context) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:375
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
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:187
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)
double toDouble(bool *ok) const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
static const QString EXPR_OFFSET
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
QSize defaultSize() const
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
#define DEFAULT_SVGMARKER_ANGLE
static const QString EXPR_SIZE
double mapRotation() const
Return current map rotation in degrees.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
bool isNull() const
#define DEFAULT_SIMPLEMARKER_NAME
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
const QColor & color() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
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.
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&#39;s name from its path.
QColor color() const
void clear()
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
void setFont(const QFont &font)
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
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)
QTransform & scale(qreal sx, qreal sy)
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
void fill(uint pixelValue)
static QString encodePoint(QPointF point)
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setPath(const QString &path)
void setPen(const QColor &color)
int width() const
void lineTo(const QPointF &endPoint)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:363
#define DEFAULT_SCALE_METHOD
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QMatrix & translate(qreal dx, qreal dy)
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setFillColor(const QColor &color) override
Set fill color.
QgsFontMarkerSymbolLayerV2(const QString &fontFamily=DEFAULT_FONTMARKER_FONT, QChar chr=DEFAULT_FONTMARKER_CHR, double pointSize=DEFAULT_FONTMARKER_SIZE, const QColor &color=DEFAULT_FONTMARKER_COLOR, double angle=DEFAULT_FONTMARKER_ANGLE)
bool prepareShape(const QString &name=QString())
QgsSymbolV2::ScaleMethod mScaleMethod
static QString symbolNameToPath(QString name)
Get symbol&#39;s path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) 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
QColor selectionColor() const
QgsMapUnitScale mapUnitScale() const override
void setWidthF(qreal width)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolV2RenderContext &context) override
void setBrush(const QBrush &brush)
void drawText(const QPointF &position, const QString &text)
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
#define DEFAULT_FONTMARKER_ANGLE
QgsSymbolV2::OutputUnit outputUnit() const override
static const QString EXPR_FILL
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
HorizontalAnchorPoint mHorizontalAnchorPoint
ushort unicode() const
QgsSvgMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setColor(const QColor &color)
virtual Q_DECL_DEPRECATED void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
virtual QColor color() const
The fill color.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
static Qt::PenStyle decodePenStyle(const QString &str)
static const QString EXPR_OUTLINE_STYLE
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
int logicalDpiX() const
int logicalDpiY() const
QgsSymbolV2::OutputUnit mOutlineWidthUnit
#define DEFAULT_SVGMARKER_SIZE
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
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)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
static const QString EXPR_COLOR
static const QString EXPR_ANGLE
QRect mapRect(const QRect &rectangle) const
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
bool forceVectorOutput() 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
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
#define DEFAULT_SVGMARKER_NAME
QMatrix & rotate(qreal degrees)
#define DEFAULT_SIMPLEMARKER_SIZE
void writeCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width)
Write circle (as polyline)
void setShift(QPointF shift)
QgsSymbolV2::ScaleMethod scaleMethod() const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
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.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:87
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
static const QString EXPR_NAME
QgsSvgMarkerSymbolLayerV2(const QString &name=DEFAULT_SVGMARKER_NAME, double size=DEFAULT_SVGMARKER_SIZE, double angle=DEFAULT_SVGMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
bool isEmpty() const
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:346
QDomElement firstChildElement(const QString &tagName) const
bool preparePath(QString name=QString())
int height() const
int count(const T &value) const
static const QString EXPR_COLOR_BORDER
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
qreal widthF() const
void translate(const QPointF &offset)
QColor fillColor() const override
Get fill color.
QgsSymbolV2::OutputUnit mOffsetUnit
void setAlphaF(qreal alpha)
virtual void setColor(const QColor &color)
The fill color.
void startRender(QgsSymbolV2RenderContext &context) override
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
int height() const
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
void startRender(QgsSymbolV2RenderContext &context) override
VerticalAnchorPoint mVerticalAnchorPoint
QgsSymbolV2::OutputUnit mSizeUnit
Calculate scale by the area.
Definition: qgssymbolv2.h:89
QgsMapUnitScale mOffsetMapUnitScale
void drawPicture(const QPointF &point, const QPicture &picture)
static const QString EXPR_OUTLINE
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
double rasterScaleFactor() const
int height() const
QDomElement createElement(const QString &tagName)
qreal height() const
void map(int x, int y, int *tx, int *ty) const
int size() const
void setAngle(double angle)
double scaleFactor() const
bool begin(QPaintDevice *device)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setColor(const QColor &color)
QgsFontMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
QColor outlineColor() const override
Get outline color.
QgsSimpleMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
qreal width() const
QColor outlineColor() const override
Get outline color.
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
QMatrix & scale(qreal sx, qreal sy)
void setOutputSize(const QRectF &r)
const T value(const Key &key) const
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &borderColor=QColor(), double borderWidth=-1, double size=-1)
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR
void setOutlineColor(const QColor &color) override
Set outline color.