QGIS API Documentation  2.14.0-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 
702 
703  // <Rotation>
704  QString angleFunc;
705  bool ok;
706  double angle = props.value( "angle", "0" ).toDouble( &ok );
707  if ( !ok )
708  {
709  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
710  }
711  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
712  {
713  angleFunc = QString::number( angle + mAngle );
714  }
715  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
716 
717  // <Displacement>
719 }
720 
721 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
722 {
723  Q_UNUSED( mmScaleFactor );
724  Q_UNUSED( mapUnitScaleFactor );
725 #if 0
726  QString ogrType = "3"; //default is circle
727  if ( mName == "square" )
728  {
729  ogrType = "5";
730  }
731  else if ( mName == "triangle" )
732  {
733  ogrType = "7";
734  }
735  else if ( mName == "star" )
736  {
737  ogrType = "9";
738  }
739  else if ( mName == "circle" )
740  {
741  ogrType = "3";
742  }
743  else if ( mName == "cross" )
744  {
745  ogrType = "0";
746  }
747  else if ( mName == "x" || mName == "cross2" )
748  {
749  ogrType = "1";
750  }
751  else if ( mName == "line" )
752  {
753  ogrType = "10";
754  }
755 
756  QString ogrString;
757  ogrString.append( "SYMBOL(" );
758  ogrString.append( "id:" );
759  ogrString.append( '\"' );
760  ogrString.append( "ogr-sym-" );
761  ogrString.append( ogrType );
762  ogrString.append( '\"' );
763  ogrString.append( ",c:" );
764  ogrString.append( mColor.name() );
765  ogrString.append( ",o:" );
766  ogrString.append( mBorderColor.name() );
767  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
768  ogrString.append( ')' );
769  return ogrString;
770 #endif //0
771 
772  QString ogrString;
773  ogrString.append( "PEN(" );
774  ogrString.append( "c:" );
775  ogrString.append( mColor.name() );
776  ogrString.append( ",w:" );
777  ogrString.append( QString::number( mSize ) );
778  ogrString.append( "mm" );
779  ogrString.append( ")" );
780  return ogrString;
781 }
782 
784 {
785  QgsDebugMsg( "Entered." );
786 
787  QDomElement graphicElem = element.firstChildElement( "Graphic" );
788  if ( graphicElem.isNull() )
789  return nullptr;
790 
791  QString name = "square";
793  double borderWidth, size;
794  Qt::PenStyle borderStyle;
795 
796  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
797  return nullptr;
798 
799  double angle = 0.0;
800  QString angleFunc;
801  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
802  {
803  bool ok;
804  double d = angleFunc.toDouble( &ok );
805  if ( ok )
806  angle = d;
807  }
808 
809  QPointF offset;
811 
812  QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
813  m->setAngle( angle );
814  m->setOffset( offset );
815  m->setOutlineStyle( borderStyle );
816  return m;
817 }
818 
820 {
821  Q_UNUSED( context );
822 
823  if ( mPolygon.count() != 0 )
824  {
825  p->drawPolygon( mPolygon );
826  }
827  else
828  {
829  p->drawPath( mPath );
830  }
831 }
832 
833 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext *context, const QgsFeature*, QPointF shift ) const
834 {
835  //data defined size?
836  double size = mSize;
837 
838  bool hasDataDefinedSize = false;
839  if ( context )
840  {
842  }
843 
844  //data defined size
845  bool ok = true;
846  if ( hasDataDefinedSize )
847  {
849  {
850  context->setOriginalValueVariable( mSize );
852  }
853 
854  if ( ok )
855  {
856  switch ( mScaleMethod )
857  {
859  size = sqrt( size );
860  break;
862  break;
863  }
864  }
865 
867  }
868  if ( mSizeUnit == QgsSymbolV2::MM )
869  {
870  size *= mmMapUnitScaleFactor;
871  }
872  double halfSize = size / 2.0;
873 
874  //outlineWidth
875  double outlineWidth = mOutlineWidth;
876 
878  {
881  }
882  if ( mSizeUnit == QgsSymbolV2::MM )
883  {
884  outlineWidth *= mmMapUnitScaleFactor;
885  }
886 
887  //color
888  QColor pc = mPen.color();
889  QColor bc = mBrush.color();
891  {
894  if ( ok )
895  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
896  }
898  {
901  if ( ok )
902  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
903  }
904 
905  //offset
906  double offsetX = 0;
907  double offsetY = 0;
908  if ( context )
909  {
910  markerOffset( *context, offsetX, offsetY );
911  }
912  QPointF off( offsetX, offsetY );
913 
914  //angle
915  double angle = mAngle + mLineAngle;
917  {
918  context->setOriginalValueVariable( mAngle );
920  }
921 
922  QString name( mName );
924  {
925  context->setOriginalValueVariable( mName );
927  }
928 
929  angle = -angle; //rotation in Qt is counterclockwise
930  if ( angle )
931  off = _rotatedOffset( off, angle );
932 
933  if ( mSizeUnit == QgsSymbolV2::MM )
934  {
935  off *= mmMapUnitScaleFactor;
936  }
937 
938  QTransform t;
939  t.translate( shift.x() + offsetX, shift.y() + offsetY );
940 
941  if ( !qgsDoubleNear( angle, 0.0 ) )
942  t.rotate( angle );
943 
944  QPolygonF polygon;
945  if ( prepareShape( name, polygon ) )
946  {
947  t.scale( halfSize, -halfSize );
948 
949  polygon = t.map( polygon );
950 
951  QgsPolygon p( 1 );
952  p.resize( 1 );
953  p[0].resize( polygon.size() + 1 );
954  int i = 0;
955  for ( i = 0; i < polygon.size(); i++ )
956  p[0][i] = polygon[i];
957  p[0][i] = p[0][0];
958 
959  if ( mBrush.style() != Qt::NoBrush )
960  e.writePolygon( p, layerName, "SOLID", bc );
961  if ( mPen.style() != Qt::NoPen )
962  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
963  }
964  else if ( name == "circle" )
965  {
966  if ( mBrush.style() != Qt::NoBrush )
967  e.writeFilledCircle( layerName, bc, shift, halfSize );
968  if ( mPen.style() != Qt::NoPen )
969  e.writeCircle( layerName, pc, shift, halfSize, "CONTINUOUS", outlineWidth );
970  }
971  else if ( name == "line" )
972  {
973  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
974  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
975 
976  if ( mPen.style() != Qt::NoPen )
977  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
978  }
979  else if ( name == "cross" )
980  {
981  if ( mPen.style() != Qt::NoPen )
982  {
983  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
984  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
985  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
986  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
987 
988  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
989  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
990  }
991  }
992  else if ( name == "x" || name == "cross2" )
993  {
994  if ( mPen.style() != Qt::NoPen )
995  {
996  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
997  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
998  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
999  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1000 
1001  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1002  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
1003  }
1004  }
1005  else if ( name == "arrowhead" )
1006  {
1007  if ( mPen.style() != Qt::NoPen )
1008  {
1009  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1010  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1011  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1012 
1013  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1014  e.writeLine( pt3, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1015  }
1016  }
1017  else
1018  {
1019  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( name ) );
1020  return false;
1021  }
1022 
1023  return true;
1024 }
1025 
1026 
1028 {
1030  mOutlineWidthUnit = unit;
1031 }
1032 
1034 {
1036  {
1037  return mOutlineWidthUnit;
1038  }
1039  return QgsSymbolV2::Mixed;
1040 }
1041 
1043 {
1045  mOutlineWidthMapUnitScale = scale;
1046 }
1047 
1049 {
1051  {
1053  }
1054  return QgsMapUnitScale();
1055 }
1056 
1058 {
1059  bool hasDataDefinedSize = false;
1060  double scaledSize = calculateSize( context, hasDataDefinedSize );
1061 
1062  bool hasDataDefinedRotation = false;
1063  QPointF offset;
1064  double angle = 0;
1065  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
1066 
1068  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1069 
1070  QMatrix transform;
1071 
1072  // move to the desired position
1073  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
1074 
1075  if ( !qgsDoubleNear( angle, 0.0 ) )
1076  transform.rotate( angle );
1077 
1078  double penWidth = 0.0;
1079  bool ok = true;
1081  {
1084  if ( ok )
1085  {
1087  }
1088  }
1090  {
1093  if ( ok && outlineStyle == "no" )
1094  {
1095  penWidth = 0.0;
1096  }
1097  }
1098  //antialiasing
1099  penWidth += pixelSize;
1100 
1101  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1102  -scaledSize / 2.0,
1103  scaledSize,
1104  scaledSize ) );
1105 
1106  //extend bounds by pen width / 2.0
1107  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1108  penWidth / 2.0, penWidth / 2.0 );
1109 
1110  return symbolBounds;
1111 }
1112 
1114 
1115 
1117 {
1119  mSize = size;
1120  mAngle = angle;
1121  mOffset = QPointF( 0, 0 );
1123  mOutlineWidth = 0.2;
1125  mColor = QColor( Qt::black );
1126  mOutlineColor = QColor( Qt::black );
1127 }
1128 
1129 
1131 {
1133  double size = DEFAULT_SVGMARKER_SIZE;
1134  double angle = DEFAULT_SVGMARKER_ANGLE;
1136 
1137  if ( props.contains( "name" ) )
1138  name = props["name"];
1139  if ( props.contains( "size" ) )
1140  size = props["size"].toDouble();
1141  if ( props.contains( "angle" ) )
1142  angle = props["angle"].toDouble();
1143  if ( props.contains( "scale_method" ) )
1144  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1145 
1146  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1147 
1148  //we only check the svg default parameters if necessary, since it could be expensive
1149  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1150  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1151  {
1153  double fillOpacity = 1.0;
1154  double outlineOpacity = 1.0;
1155  double outlineWidth;
1156  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1157  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1158  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1159  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1160  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1161  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1162  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1163  if ( hasDefaultFillColor )
1164  {
1165  m->setFillColor( fillColor );
1166  }
1167  if ( hasDefaultFillOpacity )
1168  {
1169  QColor c = m->fillColor();
1170  c.setAlphaF( fillOpacity );
1171  m->setFillColor( c );
1172  }
1173  if ( hasDefaultOutlineColor )
1174  {
1175  m->setOutlineColor( outlineColor );
1176  }
1177  if ( hasDefaultOutlineWidth )
1178  {
1179  m->setOutlineWidth( outlineWidth );
1180  }
1181  if ( hasDefaultOutlineOpacity )
1182  {
1183  QColor c = m->outlineColor();
1184  c.setAlphaF( outlineOpacity );
1185  m->setOutlineColor( c );
1186  }
1187  }
1188 
1189  if ( props.contains( "size_unit" ) )
1190  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1191  if ( props.contains( "size_map_unit_scale" ) )
1192  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1193  if ( props.contains( "offset" ) )
1194  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1195  if ( props.contains( "offset_unit" ) )
1196  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1197  if ( props.contains( "offset_map_unit_scale" ) )
1198  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1199  if ( props.contains( "fill" ) )
1200  {
1201  //pre 2.5 projects used "fill"
1202  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1203  }
1204  else if ( props.contains( "color" ) )
1205  {
1206  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1207  }
1208  if ( props.contains( "outline" ) )
1209  {
1210  //pre 2.5 projects used "outline"
1211  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1212  }
1213  else if ( props.contains( "outline_color" ) )
1214  {
1215  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1216  }
1217  else if ( props.contains( "line_color" ) )
1218  {
1219  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1220  }
1221 
1222  if ( props.contains( "outline-width" ) )
1223  {
1224  //pre 2.5 projects used "outline-width"
1225  m->setOutlineWidth( props["outline-width"].toDouble() );
1226  }
1227  else if ( props.contains( "outline_width" ) )
1228  {
1229  m->setOutlineWidth( props["outline_width"].toDouble() );
1230  }
1231  else if ( props.contains( "line_width" ) )
1232  {
1233  m->setOutlineWidth( props["line_width"].toDouble() );
1234  }
1235 
1236  if ( props.contains( "outline_width_unit" ) )
1237  {
1238  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1239  }
1240  else if ( props.contains( "line_width_unit" ) )
1241  {
1242  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1243  }
1244  if ( props.contains( "outline_width_map_unit_scale" ) )
1245  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1246 
1247  if ( props.contains( "horizontal_anchor_point" ) )
1248  {
1249  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1250  }
1251  if ( props.contains( "vertical_anchor_point" ) )
1252  {
1253  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1254  }
1255 
1256  m->restoreDataDefinedProperties( props );
1257 
1258  return m;
1259 }
1260 
1262 {
1263  mPath = path;
1264  QColor defaultFillColor, defaultOutlineColor;
1265  double outlineWidth, fillOpacity, outlineOpacity;
1266  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1267  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1268  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1269  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1270  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1271  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1272  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1273 
1274  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1275  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1276 
1277  if ( hasDefaultFillColor )
1278  {
1279  defaultFillColor.setAlphaF( newFillOpacity );
1280  setFillColor( defaultFillColor );
1281  }
1282  if ( hasDefaultFillOpacity )
1283  {
1284  QColor c = fillColor();
1285  c.setAlphaF( fillOpacity );
1286  setFillColor( c );
1287  }
1288  if ( hasDefaultOutlineColor )
1289  {
1290  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1291  setOutlineColor( defaultOutlineColor );
1292  }
1293  if ( hasDefaultOutlineWidth )
1294  {
1295  setOutlineWidth( outlineWidth );
1296  }
1297  if ( hasDefaultOutlineOpacity )
1298  {
1299  QColor c = outlineColor();
1300  c.setAlphaF( outlineOpacity );
1301  setOutlineColor( c );
1302  }
1303 }
1304 
1305 
1307 {
1308  return "SvgMarker";
1309 }
1310 
1312 {
1313  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1314  Q_UNUSED( context );
1315  prepareExpressions( context );
1316 }
1317 
1319 {
1320  Q_UNUSED( context );
1321 }
1322 
1324 {
1325  QPainter *p = context.renderContext().painter();
1326  if ( !p )
1327  return;
1328 
1329  bool hasDataDefinedSize = false;
1330  double scaledSize = calculateSize( context, hasDataDefinedSize );
1332 
1333  //don't render symbols with size below one or above 10,000 pixels
1334  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1335  {
1336  return;
1337  }
1338 
1339  p->save();
1340 
1341  QPointF outputOffset;
1342  double angle = 0.0;
1343  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1344 
1345  p->translate( point + outputOffset );
1346 
1347  bool rotated = !qgsDoubleNear( angle, 0 );
1348  if ( rotated )
1349  p->rotate( angle );
1350 
1351  QString path = mPath;
1353  {
1354  context.setOriginalValueVariable( mPath );
1356  }
1357 
1358  double outlineWidth = mOutlineWidth;
1360  {
1363  }
1365 
1367  bool ok = false;
1369  {
1372  if ( ok )
1373  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1374  }
1375 
1376  QColor outlineColor = mOutlineColor;
1378  {
1381  if ( ok )
1382  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1383  }
1384 
1385  bool fitsInCache = true;
1386  bool usePict = true;
1387  double hwRatio = 1.0;
1388  if ( !context.renderContext().forceVectorOutput() && !rotated )
1389  {
1390  usePict = false;
1391  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1392  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1393  if ( fitsInCache && img.width() > 1 )
1394  {
1395  //consider transparency
1396  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1397  {
1398  QImage transparentImage = img.copy();
1399  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1400  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1401  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
1402  }
1403  else
1404  {
1405  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1406  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
1407  }
1408  }
1409  }
1410 
1411  if ( usePict || !fitsInCache )
1412  {
1413  p->setOpacity( context.alpha() );
1414  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1416 
1417  if ( pct.width() > 1 )
1418  {
1419  p->save();
1420  _fixQPictureDPI( p );
1421  p->drawPicture( 0, 0, pct );
1422  p->restore();
1423  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
1424  }
1425  }
1426 
1427  if ( context.selected() )
1428  {
1429  QPen pen( context.renderContext().selectionColor() );
1431  if ( penWidth > size / 20 )
1432  {
1433  // keep the pen width from covering symbol
1434  penWidth = size / 20;
1435  }
1436  double penOffset = penWidth / 2;
1437  pen.setWidth( penWidth );
1438  p->setPen( pen );
1439  p->setBrush( Qt::NoBrush );
1440  double wSize = size + penOffset;
1441  double hSize = size * hwRatio + penOffset;
1442  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1443  }
1444 
1445  p->restore();
1446 }
1447 
1448 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
1449 {
1450  double scaledSize = mSize;
1452 
1453  bool ok = true;
1455  {
1456  context.setOriginalValueVariable( mSize );
1457  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
1458  }
1459 
1460  if ( hasDataDefinedSize && ok )
1461  {
1462  switch ( mScaleMethod )
1463  {
1465  scaledSize = sqrt( scaledSize );
1466  break;
1468  break;
1469  }
1470  }
1471 
1472  return scaledSize;
1473 }
1474 
1475 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
1476 {
1477  //offset
1478  double offsetX = 0;
1479  double offsetY = 0;
1480  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1481  offset = QPointF( offsetX, offsetY );
1482 
1483  angle = mAngle + mLineAngle;
1485  {
1486  context.setOriginalValueVariable( mAngle );
1488  }
1489 
1491  if ( hasDataDefinedRotation )
1492  {
1493  // For non-point markers, "dataDefinedRotation" means following the
1494  // shape (shape-data defined). For them, "field-data defined" does
1495  // not work at all. TODO: if "field-data defined" ever gets implemented
1496  // we'll need a way to distinguish here between the two, possibly
1497  // using another flag in renderHints()
1498  const QgsFeature* f = context.feature();
1499  if ( f )
1500  {
1501  const QgsGeometry *g = f->constGeometry();
1502  if ( g && g->type() == QGis::Point )
1503  {
1504  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1505  angle += m2p.mapRotation();
1506  }
1507  }
1508  }
1509 
1510  if ( angle )
1511  offset = _rotatedOffset( offset, angle );
1512 }
1513 
1514 
1516 {
1517  QgsStringMap map;
1519  map["size"] = QString::number( mSize );
1520  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1521  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1522  map["angle"] = QString::number( mAngle );
1523  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1524  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1525  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1526  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1527  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1528  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
1529  map["outline_width"] = QString::number( mOutlineWidth );
1530  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1531  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1532  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1533  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1534 
1536  return map;
1537 }
1538 
1540 {
1542  m->setColor( mColor );
1543  m->setOutlineColor( mOutlineColor );
1547  m->setOffset( mOffset );
1548  m->setOffsetUnit( mOffsetUnit );
1550  m->setSizeUnit( mSizeUnit );
1555  copyPaintEffect( m );
1556  return m;
1557 }
1558 
1560 {
1562  mOutlineWidthUnit = unit;
1563 }
1564 
1566 {
1568  if ( unit != mOutlineWidthUnit )
1569  {
1570  return QgsSymbolV2::Mixed;
1571  }
1572  return unit;
1573 }
1574 
1576 {
1578  mOutlineWidthMapUnitScale = scale;
1579 }
1580 
1582 {
1584  {
1586  }
1587  return QgsMapUnitScale();
1588 }
1589 
1591 {
1592  // <Graphic>
1593  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1594  element.appendChild( graphicElem );
1595 
1596  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
1597 
1598  // <Rotation>
1599  QString angleFunc;
1600  bool ok;
1601  double angle = props.value( "angle", "0" ).toDouble( &ok );
1602  if ( !ok )
1603  {
1604  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1605  }
1606  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1607  {
1608  angleFunc = QString::number( angle + mAngle );
1609  }
1610 
1611  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1612 
1613  // <Displacement>
1615 }
1616 
1618 {
1619  QgsDebugMsg( "Entered." );
1620 
1621  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1622  if ( graphicElem.isNull() )
1623  return nullptr;
1624 
1625  QString path, mimeType;
1626  QColor fillColor;
1627  double size;
1628 
1629  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1630  return nullptr;
1631 
1632  if ( mimeType != "image/svg+xml" )
1633  return nullptr;
1634 
1635  double angle = 0.0;
1636  QString angleFunc;
1637  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1638  {
1639  bool ok;
1640  double d = angleFunc.toDouble( &ok );
1641  if ( ok )
1642  angle = d;
1643  }
1644 
1645  QPointF offset;
1647 
1649  m->setFillColor( fillColor );
1650  //m->setOutlineColor( outlineColor );
1651  //m->setOutlineWidth( outlineWidth );
1652  m->setAngle( angle );
1653  m->setOffset( offset );
1654  return m;
1655 }
1656 
1657 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext *context, const QgsFeature*,
1658  QPointF shift ) const
1659 {
1660  Q_UNUSED( layerName );
1661  Q_UNUSED( shift ); //todo...
1662 
1663  //size
1664  double size = mSize;
1665 
1667 
1668  bool ok = true;
1670  {
1671  context->setOriginalValueVariable( mSize );
1673  }
1674 
1675  if ( hasDataDefinedSize && ok )
1676  {
1677  switch ( mScaleMethod )
1678  {
1680  size = sqrt( size );
1681  break;
1683  break;
1684  }
1685  }
1686 
1687  if ( mSizeUnit == QgsSymbolV2::MM )
1688  {
1689  size *= mmMapUnitScaleFactor;
1690  }
1691 
1692  double halfSize = size / 2.0;
1693 
1694  //offset, angle
1695  QPointF offset = mOffset;
1696 
1698  {
1701  if ( ok )
1702  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
1703  }
1704  double offsetX = offset.x();
1705  double offsetY = offset.y();
1706  if ( mSizeUnit == QgsSymbolV2::MM )
1707  {
1708  offsetX *= mmMapUnitScaleFactor;
1709  offsetY *= mmMapUnitScaleFactor;
1710  }
1711 
1712  QPointF outputOffset( offsetX, offsetY );
1713 
1714  double angle = mAngle + mLineAngle;
1716  {
1717  context->setOriginalValueVariable( mAngle );
1719  }
1720  //angle = -angle; //rotation in Qt is counterclockwise
1721  if ( angle )
1722  outputOffset = _rotatedOffset( outputOffset, angle );
1723 
1724  QString path = mPath;
1726  {
1727  context->setOriginalValueVariable( mPath );
1729  }
1730 
1731  double outlineWidth = mOutlineWidth;
1733  {
1736  }
1738 
1741  {
1744  if ( ok )
1745  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1746  }
1747 
1748  QColor outlineColor = mOutlineColor;
1750  {
1751  context->setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mOutlineColor ) );
1753  if ( ok )
1754  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1755  }
1756 
1757  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
1758  context->renderContext().scaleFactor(),
1759  context->renderContext().rasterScaleFactor() );
1760 
1761  //if current entry image is 0: cache image for entry
1762  // checks to see if image will fit into cache
1763  //update stats for memory usage
1764  QSvgRenderer r( svgContent );
1765  if ( !r.isValid() )
1766  {
1767  return false;
1768  }
1769 
1770  QgsDxfPaintDevice pd( &e );
1771  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
1772 
1773  QPainter p;
1774  p.begin( &pd );
1775  if ( !qgsDoubleNear( angle, 0.0 ) )
1776  {
1777  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
1778  p.rotate( angle );
1779  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
1780  }
1781  pd.setShift( shift );
1782  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
1783  pd.setLayer( layerName );
1784  r.render( &p );
1785  p.end();
1786  return true;
1787 }
1788 
1790 {
1791  bool hasDataDefinedSize = false;
1792  double scaledSize = calculateSize( context, hasDataDefinedSize );
1794 
1795  //don't render symbols with size below one or above 10,000 pixels
1796  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
1797  {
1798  return QRectF();
1799  }
1800 
1801  QPointF outputOffset;
1802  double angle = 0.0;
1803  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1804 
1805  QString path = mPath;
1807  {
1808  context.setOriginalValueVariable( mPath );
1810  }
1811 
1812  double outlineWidth = mOutlineWidth;
1814  {
1817  }
1819 
1820  //need to get colors to take advantage of cached SVGs
1822  bool ok = false;
1824  {
1827  if ( ok )
1828  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1829  }
1830 
1831  QColor outlineColor = mOutlineColor;
1833  {
1836  if ( ok )
1837  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1838  }
1839 
1840  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
1841  context.renderContext().scaleFactor(),
1842  context.renderContext().rasterScaleFactor() );
1843 
1844  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
1845  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1846 
1847  QMatrix transform;
1848 
1849  // move to the desired position
1850  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
1851 
1852  if ( !qgsDoubleNear( angle, 0.0 ) )
1853  transform.rotate( angle );
1854 
1855  //antialiasing
1856  outlineWidth += pixelSize / 2.0;
1857 
1858  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1859  -scaledHeight / 2.0,
1860  scaledSize,
1861  scaledHeight ) );
1862 
1863  //extend bounds by pen width / 2.0
1864  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
1865  outlineWidth / 2.0, outlineWidth / 2.0 );
1866 
1867  return symbolBounds;
1868 
1869 }
1870 
1872 
1873 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
1874  : mFontMetrics( nullptr )
1875  , mChrWidth( 0 )
1876 {
1878  mChr = chr;
1879  mColor = color;
1880  mAngle = angle;
1881  mSize = pointSize;
1882  mOrigSize = pointSize;
1884  mOffset = QPointF( 0, 0 );
1886 }
1887 
1889 {
1890  delete mFontMetrics;
1891 }
1892 
1894 {
1897  double pointSize = DEFAULT_FONTMARKER_SIZE;
1900 
1901  if ( props.contains( "font" ) )
1902  fontFamily = props["font"];
1903  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
1904  chr = props["chr"].at( 0 );
1905  if ( props.contains( "size" ) )
1906  pointSize = props["size"].toDouble();
1907  if ( props.contains( "color" ) )
1908  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
1909  if ( props.contains( "angle" ) )
1910  angle = props["angle"].toDouble();
1911 
1912  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
1913  if ( props.contains( "offset" ) )
1914  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1915  if ( props.contains( "offset_unit" ) )
1916  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
1917  if ( props.contains( "offset_map_unit_scale" ) )
1918  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
1919  if ( props.contains( "size_unit" ) )
1920  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1921  if ( props.contains( "size_map_unit_scale" ) )
1922  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1923  if ( props.contains( "horizontal_anchor_point" ) )
1924  {
1925  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1926  }
1927  if ( props.contains( "vertical_anchor_point" ) )
1928  {
1929  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1930  }
1931 
1932  m->restoreDataDefinedProperties( props );
1933 
1934  return m;
1935 }
1936 
1938 {
1939  return "FontMarker";
1940 }
1941 
1943 {
1944  mFont = QFont( mFontFamily );
1946  delete mFontMetrics;
1947  mFontMetrics = new QFontMetrics( mFont );
1949  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
1950  mOrigSize = mSize; // save in case the size would be data defined
1951  prepareExpressions( context );
1952 }
1953 
1955 {
1956  Q_UNUSED( context );
1957 }
1958 
1959 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
1960 {
1961  charOffset = mChrOffset;
1962  QString charToRender = mChr;
1964  {
1965  context.setOriginalValueVariable( mChr );
1967  if ( charToRender != mChr )
1968  {
1969  charWidth = mFontMetrics->width( charToRender );
1970  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
1971  }
1972  }
1973  return charToRender;
1974 }
1975 
1976 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
1977  double scaledSize,
1978  bool& hasDataDefinedRotation,
1979  QPointF& offset,
1980  double& angle ) const
1981 {
1982  //offset
1983  double offsetX = 0;
1984  double offsetY = 0;
1985  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1986  offset = QPointF( offsetX, offsetY );
1987 
1988  //angle
1989  bool ok = true;
1990  angle = mAngle + mLineAngle;
1991  bool usingDataDefinedRotation = false;
1993  {
1994  context.setOriginalValueVariable( angle );
1996  usingDataDefinedRotation = ok;
1997  }
1998 
1999  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2000  if ( hasDataDefinedRotation )
2001  {
2002  // For non-point markers, "dataDefinedRotation" means following the
2003  // shape (shape-data defined). For them, "field-data defined" does
2004  // not work at all. TODO: if "field-data defined" ever gets implemented
2005  // we'll need a way to distinguish here between the two, possibly
2006  // using another flag in renderHints()
2007  const QgsFeature* f = context.feature();
2008  if ( f )
2009  {
2010  const QgsGeometry *g = f->constGeometry();
2011  if ( g && g->type() == QGis::Point )
2012  {
2013  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2014  angle += m2p.mapRotation();
2015  }
2016  }
2017  }
2018 
2019  if ( angle )
2020  offset = _rotatedOffset( offset, angle );
2021 }
2022 
2023 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2024 {
2025  double scaledSize = mSize;
2027 
2028  bool ok = true;
2030  {
2031  context.setOriginalValueVariable( mSize );
2032  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2033  }
2034 
2035  if ( hasDataDefinedSize && ok )
2036  {
2037  switch ( mScaleMethod )
2038  {
2040  scaledSize = sqrt( scaledSize );
2041  break;
2043  break;
2044  }
2045  }
2046  return scaledSize;
2047 }
2048 
2050 {
2051  QPainter *p = context.renderContext().painter();
2052  if ( !p )
2053  return;
2054 
2055  QColor penColor = mColor;
2056  bool ok;
2058  {
2061  if ( ok )
2062  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2063  }
2064  penColor = context.selected() ? context.renderContext().selectionColor() : penColor;
2065  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2066 
2067  p->setPen( penColor );
2068  p->setFont( mFont );
2069  p->save();
2070 
2071  QPointF chrOffset = mChrOffset;
2072  double chrWidth;
2073  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2074 
2075  double sizeToRender = calculateSize( context );
2076 
2077  bool hasDataDefinedRotation = false;
2078  QPointF offset;
2079  double angle = 0;
2080  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2081 
2082  p->translate( point + offset );
2083 
2084  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2085  {
2086  double s = sizeToRender / mOrigSize;
2087  p->scale( s, s );
2088  }
2089 
2090  if ( !qgsDoubleNear( angle, 0 ) )
2091  p->rotate( angle );
2092 
2093  p->drawText( -chrOffset, charToRender );
2094  p->restore();
2095 }
2096 
2098 {
2099  QgsStringMap props;
2100  props["font"] = mFontFamily;
2101  props["chr"] = mChr;
2102  props["size"] = QString::number( mSize );
2103  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2104  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2105  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2106  props["angle"] = QString::number( mAngle );
2107  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2108  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2109  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2110  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2111  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2112 
2113  //data define properties
2114  saveDataDefinedProperties( props );
2115 
2116  return props;
2117 }
2118 
2120 {
2122  m->setOffset( mOffset );
2123  m->setOffsetUnit( mOffsetUnit );
2125  m->setSizeUnit( mSizeUnit );
2130  copyPaintEffect( m );
2131  return m;
2132 }
2133 
2135 {
2136  // <Graphic>
2137  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2138  element.appendChild( graphicElem );
2139 
2140  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2141  int markIndex = mChr.unicode();
2142  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
2143 
2144  // <Rotation>
2145  QString angleFunc;
2146  bool ok;
2147  double angle = props.value( "angle", "0" ).toDouble( &ok );
2148  if ( !ok )
2149  {
2150  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2151  }
2152  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2153  {
2154  angleFunc = QString::number( angle + mAngle );
2155  }
2156  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2157 
2158  // <Displacement>
2160 }
2161 
2163 {
2164  QPointF chrOffset = mChrOffset;
2165  double chrWidth = mChrWidth;
2166  //calculate width of rendered character
2167  ( void )characterToRender( context, chrOffset, chrWidth );
2168 
2169  if ( !mFontMetrics )
2170  mFontMetrics = new QFontMetrics( mFont );
2171 
2172  double scaledSize = calculateSize( context );
2173  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2174  {
2175  chrWidth *= scaledSize / mOrigSize;
2176  }
2177 
2178  bool hasDataDefinedRotation = false;
2179  QPointF offset;
2180  double angle = 0;
2181  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2183 
2184  QMatrix transform;
2185 
2186  // move to the desired position
2187  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2188 
2189  if ( !qgsDoubleNear( angle, 0.0 ) )
2190  transform.rotate( angle );
2191 
2192  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2193  -scaledSize / 2.0,
2194  chrWidth,
2195  scaledSize ) );
2196  return symbolBounds;
2197 }
2198 
2200 {
2201  QgsDebugMsg( "Entered." );
2202 
2203  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2204  if ( graphicElem.isNull() )
2205  return nullptr;
2206 
2207  QString name, format;
2208  QColor color;
2209  double size;
2210  int chr;
2211 
2212  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2213  return nullptr;
2214 
2215  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2216  return nullptr;
2217 
2218  QString fontFamily = name.mid( 6 );
2219 
2220  double angle = 0.0;
2221  QString angleFunc;
2222  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2223  {
2224  bool ok;
2225  double d = angleFunc.toDouble( &ok );
2226  if ( ok )
2227  angle = d;
2228  }
2229 
2230  QPointF offset;
2232 
2233  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2234  m->setAngle( angle );
2235  m->setOffset( offset );
2236  return m;
2237 }
2238 
2239 
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 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)
int renderHints() const
Definition: qgssymbolv2.h:369
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)
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
QColor selectionColor() 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)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
#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
static QPointF decodePoint(const 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...
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
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: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())
double mapRotation() const
Return current map rotation in degrees.
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
#define DEFAULT_SVGMARKER_ANGLE
static const QString EXPR_SIZE
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
bool isNull() const
#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 QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
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:362
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)
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
qreal x() const
qreal y() const
void resize(int size)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:374
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)
#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
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
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)
double rasterScaleFactor() const
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
virtual QColor color() const
The fill color.
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.
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
static Qt::PenStyle decodePenStyle(const QString &str)
QgsSymbolV2::ScaleMethod scaleMethod() const
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
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
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
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 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)
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.
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.
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext *context, const QgsFeature *f, QPointF shift=QPointF(0.0, 0.0)) const override
QgsMapUnitScale mapUnitScale() const override
Qt::PenStyle outlineStyle() const
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:345
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
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
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)
const QgsMapToPixel & mapToPixel() const
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)
bool selected() const
Definition: qgssymbolv2.h:366
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)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext *context, const QgsFeature *f, QPointF shift=QPointF(0.0, 0.0)) const override
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)
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)
bool begin(QPaintDevice *device)
QPointF offset() const
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 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.
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.
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
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)
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_SIMPLEMARKER_BORDERCOLOR
void setOutlineColor(const QColor &color) override
Set outline color.