QGIS API Documentation  2.14.5-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, QPointF shift ) const
834 {
835  //data defined size?
836  double size = mSize;
837 
839 
840  //data defined size
841  bool ok = true;
842  if ( hasDataDefinedSize )
843  {
845  {
846  context.setOriginalValueVariable( mSize );
848  }
849 
850  if ( ok )
851  {
852  switch ( mScaleMethod )
853  {
855  size = sqrt( size );
856  break;
858  break;
859  }
860  }
861 
863  }
864  if ( mSizeUnit == QgsSymbolV2::MM )
865  {
866  size *= mmMapUnitScaleFactor;
867  }
868  double halfSize = size / 2.0;
869 
870  //outlineWidth
871  double outlineWidth = mOutlineWidth;
872 
874  {
877  }
878  if ( mSizeUnit == QgsSymbolV2::MM )
879  {
880  outlineWidth *= mmMapUnitScaleFactor;
881  }
882 
883  //color
884  QColor pc = mPen.color();
885  QColor bc = mBrush.color();
887  {
890  if ( ok )
891  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
892  }
894  {
897  if ( ok )
898  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
899  }
900 
901  //offset
902  double offsetX = 0;
903  double offsetY = 0;
904  markerOffset( context, offsetX, offsetY );
905 
906  QPointF off( offsetX, offsetY );
907 
908  //angle
909  double angle = mAngle + mLineAngle;
911  {
912  context.setOriginalValueVariable( mAngle );
914  }
915 
916  QString name( mName );
918  {
919  context.setOriginalValueVariable( mName );
921  }
922 
923  angle = -angle; //rotation in Qt is counterclockwise
924  if ( angle )
925  off = _rotatedOffset( off, angle );
926 
927  if ( mSizeUnit == QgsSymbolV2::MM )
928  {
929  off *= mmMapUnitScaleFactor;
930  }
931 
932  QTransform t;
933  t.translate( shift.x() + offsetX, shift.y() + offsetY );
934 
935  if ( !qgsDoubleNear( angle, 0.0 ) )
936  t.rotate( angle );
937 
938  QPolygonF polygon;
939  if ( prepareShape( name, polygon ) )
940  {
941  t.scale( halfSize, -halfSize );
942 
943  polygon = t.map( polygon );
944 
945  QgsPolygon p( 1 );
946  p.resize( 1 );
947  p[0].resize( polygon.size() + 1 );
948  int i = 0;
949  for ( i = 0; i < polygon.size(); i++ )
950  p[0][i] = polygon[i];
951  p[0][i] = p[0][0];
952 
953  if ( mBrush.style() != Qt::NoBrush )
954  e.writePolygon( p, layerName, "SOLID", bc );
955  if ( mPen.style() != Qt::NoPen )
956  e.writePolyline( p[0], layerName, "CONTINUOUS", pc, outlineWidth );
957  }
958  else if ( name == "circle" )
959  {
960  if ( mBrush.style() != Qt::NoBrush )
961  e.writeFilledCircle( layerName, bc, shift, halfSize );
962  if ( mPen.style() != Qt::NoPen )
963  e.writeCircle( layerName, pc, shift, halfSize, "CONTINUOUS", outlineWidth );
964  }
965  else if ( name == "line" )
966  {
967  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
968  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
969 
970  if ( mPen.style() != Qt::NoPen )
971  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
972  }
973  else if ( name == "cross" )
974  {
975  if ( mPen.style() != Qt::NoPen )
976  {
977  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
978  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
979  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
980  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
981 
982  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
983  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
984  }
985  }
986  else if ( name == "x" || name == "cross2" )
987  {
988  if ( mPen.style() != Qt::NoPen )
989  {
990  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
991  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
992  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
993  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
994 
995  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
996  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
997  }
998  }
999  else if ( name == "arrowhead" )
1000  {
1001  if ( mPen.style() != Qt::NoPen )
1002  {
1003  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1004  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1005  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1006 
1007  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1008  e.writeLine( pt3, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1009  }
1010  }
1011  else
1012  {
1013  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( name ) );
1014  return false;
1015  }
1016 
1017  return true;
1018 }
1019 
1020 
1022 {
1024  mOutlineWidthUnit = unit;
1025 }
1026 
1028 {
1030  {
1031  return mOutlineWidthUnit;
1032  }
1033  return QgsSymbolV2::Mixed;
1034 }
1035 
1037 {
1039  mOutlineWidthMapUnitScale = scale;
1040 }
1041 
1043 {
1045  {
1047  }
1048  return QgsMapUnitScale();
1049 }
1050 
1052 {
1053  bool hasDataDefinedSize = false;
1054  double scaledSize = calculateSize( context, hasDataDefinedSize );
1055 
1056  bool hasDataDefinedRotation = false;
1057  QPointF offset;
1058  double angle = 0;
1059  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
1060 
1062  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1063 
1064  QMatrix transform;
1065 
1066  // move to the desired position
1067  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
1068 
1069  if ( !qgsDoubleNear( angle, 0.0 ) )
1070  transform.rotate( angle );
1071 
1072  double penWidth = 0.0;
1073  bool ok = true;
1075  {
1078  if ( ok )
1079  {
1081  }
1082  }
1084  {
1087  if ( ok && outlineStyle == "no" )
1088  {
1089  penWidth = 0.0;
1090  }
1091  }
1092  //antialiasing
1093  penWidth += pixelSize;
1094 
1095  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1096  -scaledSize / 2.0,
1097  scaledSize,
1098  scaledSize ) );
1099 
1100  //extend bounds by pen width / 2.0
1101  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1102  penWidth / 2.0, penWidth / 2.0 );
1103 
1104  return symbolBounds;
1105 }
1106 
1108 
1109 
1111 {
1113  mSize = size;
1114  mAngle = angle;
1115  mOffset = QPointF( 0, 0 );
1117  mOutlineWidth = 0.2;
1119  mColor = QColor( Qt::black );
1120  mOutlineColor = QColor( Qt::black );
1121 }
1122 
1123 
1125 {
1127  double size = DEFAULT_SVGMARKER_SIZE;
1128  double angle = DEFAULT_SVGMARKER_ANGLE;
1130 
1131  if ( props.contains( "name" ) )
1132  name = props["name"];
1133  if ( props.contains( "size" ) )
1134  size = props["size"].toDouble();
1135  if ( props.contains( "angle" ) )
1136  angle = props["angle"].toDouble();
1137  if ( props.contains( "scale_method" ) )
1138  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1139 
1140  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1141 
1142  //we only check the svg default parameters if necessary, since it could be expensive
1143  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1144  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1145  {
1147  double fillOpacity = 1.0;
1148  double outlineOpacity = 1.0;
1149  double outlineWidth;
1150  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1151  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1152  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1153  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1154  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1155  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1156  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1157  if ( hasDefaultFillColor )
1158  {
1159  m->setFillColor( fillColor );
1160  }
1161  if ( hasDefaultFillOpacity )
1162  {
1163  QColor c = m->fillColor();
1164  c.setAlphaF( fillOpacity );
1165  m->setFillColor( c );
1166  }
1167  if ( hasDefaultOutlineColor )
1168  {
1169  m->setOutlineColor( outlineColor );
1170  }
1171  if ( hasDefaultOutlineWidth )
1172  {
1173  m->setOutlineWidth( outlineWidth );
1174  }
1175  if ( hasDefaultOutlineOpacity )
1176  {
1177  QColor c = m->outlineColor();
1178  c.setAlphaF( outlineOpacity );
1179  m->setOutlineColor( c );
1180  }
1181  }
1182 
1183  if ( props.contains( "size_unit" ) )
1184  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1185  if ( props.contains( "size_map_unit_scale" ) )
1186  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1187  if ( props.contains( "offset" ) )
1188  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1189  if ( props.contains( "offset_unit" ) )
1190  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1191  if ( props.contains( "offset_map_unit_scale" ) )
1192  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1193  if ( props.contains( "fill" ) )
1194  {
1195  //pre 2.5 projects used "fill"
1196  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1197  }
1198  else if ( props.contains( "color" ) )
1199  {
1200  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1201  }
1202  if ( props.contains( "outline" ) )
1203  {
1204  //pre 2.5 projects used "outline"
1205  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1206  }
1207  else if ( props.contains( "outline_color" ) )
1208  {
1209  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1210  }
1211  else if ( props.contains( "line_color" ) )
1212  {
1213  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1214  }
1215 
1216  if ( props.contains( "outline-width" ) )
1217  {
1218  //pre 2.5 projects used "outline-width"
1219  m->setOutlineWidth( props["outline-width"].toDouble() );
1220  }
1221  else if ( props.contains( "outline_width" ) )
1222  {
1223  m->setOutlineWidth( props["outline_width"].toDouble() );
1224  }
1225  else if ( props.contains( "line_width" ) )
1226  {
1227  m->setOutlineWidth( props["line_width"].toDouble() );
1228  }
1229 
1230  if ( props.contains( "outline_width_unit" ) )
1231  {
1232  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1233  }
1234  else if ( props.contains( "line_width_unit" ) )
1235  {
1236  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1237  }
1238  if ( props.contains( "outline_width_map_unit_scale" ) )
1239  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1240 
1241  if ( props.contains( "horizontal_anchor_point" ) )
1242  {
1243  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1244  }
1245  if ( props.contains( "vertical_anchor_point" ) )
1246  {
1247  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1248  }
1249 
1250  m->restoreDataDefinedProperties( props );
1251 
1252  return m;
1253 }
1254 
1256 {
1257  mPath = path;
1258  QColor defaultFillColor, defaultOutlineColor;
1259  double outlineWidth, fillOpacity, outlineOpacity;
1260  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1261  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1262  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1263  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1264  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1265  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1266  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1267 
1268  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1269  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1270 
1271  if ( hasDefaultFillColor )
1272  {
1273  defaultFillColor.setAlphaF( newFillOpacity );
1274  setFillColor( defaultFillColor );
1275  }
1276  if ( hasDefaultFillOpacity )
1277  {
1278  QColor c = fillColor();
1279  c.setAlphaF( fillOpacity );
1280  setFillColor( c );
1281  }
1282  if ( hasDefaultOutlineColor )
1283  {
1284  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1285  setOutlineColor( defaultOutlineColor );
1286  }
1287  if ( hasDefaultOutlineWidth )
1288  {
1289  setOutlineWidth( outlineWidth );
1290  }
1291  if ( hasDefaultOutlineOpacity )
1292  {
1293  QColor c = outlineColor();
1294  c.setAlphaF( outlineOpacity );
1295  setOutlineColor( c );
1296  }
1297 }
1298 
1299 
1301 {
1302  return "SvgMarker";
1303 }
1304 
1306 {
1307  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1308  Q_UNUSED( context );
1309  prepareExpressions( context );
1310 }
1311 
1313 {
1314  Q_UNUSED( context );
1315 }
1316 
1318 {
1319  QPainter *p = context.renderContext().painter();
1320  if ( !p )
1321  return;
1322 
1323  bool hasDataDefinedSize = false;
1324  double scaledSize = calculateSize( context, hasDataDefinedSize );
1326 
1327  //don't render symbols with size below one or above 10,000 pixels
1328  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1329  {
1330  return;
1331  }
1332 
1333  p->save();
1334 
1335  QPointF outputOffset;
1336  double angle = 0.0;
1337  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1338 
1339  p->translate( point + outputOffset );
1340 
1341  bool rotated = !qgsDoubleNear( angle, 0 );
1342  if ( rotated )
1343  p->rotate( angle );
1344 
1345  QString path = mPath;
1347  {
1348  context.setOriginalValueVariable( mPath );
1350  }
1351 
1352  double outlineWidth = mOutlineWidth;
1354  {
1357  }
1359 
1361  bool ok = false;
1363  {
1366  if ( ok )
1367  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1368  }
1369 
1370  QColor outlineColor = mOutlineColor;
1372  {
1375  if ( ok )
1376  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1377  }
1378 
1379  bool fitsInCache = true;
1380  bool usePict = true;
1381  double hwRatio = 1.0;
1382  if ( !context.renderContext().forceVectorOutput() && !rotated )
1383  {
1384  usePict = false;
1385  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1386  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1387  if ( fitsInCache && img.width() > 1 )
1388  {
1389  //consider transparency
1390  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1391  {
1392  QImage transparentImage = img.copy();
1393  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1394  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1395  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
1396  }
1397  else
1398  {
1399  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1400  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
1401  }
1402  }
1403  }
1404 
1405  if ( usePict || !fitsInCache )
1406  {
1407  p->setOpacity( context.alpha() );
1408  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1410 
1411  if ( pct.width() > 1 )
1412  {
1413  p->save();
1414  _fixQPictureDPI( p );
1415  p->drawPicture( 0, 0, pct );
1416  p->restore();
1417  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
1418  }
1419  }
1420 
1421  if ( context.selected() )
1422  {
1423  QPen pen( context.renderContext().selectionColor() );
1425  if ( penWidth > size / 20 )
1426  {
1427  // keep the pen width from covering symbol
1428  penWidth = size / 20;
1429  }
1430  double penOffset = penWidth / 2;
1431  pen.setWidth( penWidth );
1432  p->setPen( pen );
1433  p->setBrush( Qt::NoBrush );
1434  double wSize = size + penOffset;
1435  double hSize = size * hwRatio + penOffset;
1436  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1437  }
1438 
1439  p->restore();
1440 
1442  {
1443  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
1444  p->setRenderHint( QPainter::Antialiasing );
1445  }
1446 
1447 }
1448 
1449 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
1450 {
1451  double scaledSize = mSize;
1453 
1454  bool ok = true;
1456  {
1457  context.setOriginalValueVariable( mSize );
1458  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
1459  }
1460 
1461  if ( hasDataDefinedSize && ok )
1462  {
1463  switch ( mScaleMethod )
1464  {
1466  scaledSize = sqrt( scaledSize );
1467  break;
1469  break;
1470  }
1471  }
1472 
1473  return scaledSize;
1474 }
1475 
1476 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
1477 {
1478  //offset
1479  double offsetX = 0;
1480  double offsetY = 0;
1481  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1482  offset = QPointF( offsetX, offsetY );
1483 
1484  angle = mAngle + mLineAngle;
1486  {
1487  context.setOriginalValueVariable( mAngle );
1489  }
1490 
1492  if ( hasDataDefinedRotation )
1493  {
1494  // For non-point markers, "dataDefinedRotation" means following the
1495  // shape (shape-data defined). For them, "field-data defined" does
1496  // not work at all. TODO: if "field-data defined" ever gets implemented
1497  // we'll need a way to distinguish here between the two, possibly
1498  // using another flag in renderHints()
1499  const QgsFeature* f = context.feature();
1500  if ( f )
1501  {
1502  const QgsGeometry *g = f->constGeometry();
1503  if ( g && g->type() == QGis::Point )
1504  {
1505  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1506  angle += m2p.mapRotation();
1507  }
1508  }
1509  }
1510 
1511  if ( angle )
1512  offset = _rotatedOffset( offset, angle );
1513 }
1514 
1515 
1517 {
1518  QgsStringMap map;
1520  map["size"] = QString::number( mSize );
1521  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1522  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1523  map["angle"] = QString::number( mAngle );
1524  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1525  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1526  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1527  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1528  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1529  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
1530  map["outline_width"] = QString::number( mOutlineWidth );
1531  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1532  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1533  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1534  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1535 
1537  return map;
1538 }
1539 
1541 {
1543  m->setColor( mColor );
1544  m->setOutlineColor( mOutlineColor );
1548  m->setOffset( mOffset );
1549  m->setOffsetUnit( mOffsetUnit );
1551  m->setSizeUnit( mSizeUnit );
1556  copyPaintEffect( m );
1557  return m;
1558 }
1559 
1561 {
1563  mOutlineWidthUnit = unit;
1564 }
1565 
1567 {
1569  if ( unit != mOutlineWidthUnit )
1570  {
1571  return QgsSymbolV2::Mixed;
1572  }
1573  return unit;
1574 }
1575 
1577 {
1579  mOutlineWidthMapUnitScale = scale;
1580 }
1581 
1583 {
1585  {
1587  }
1588  return QgsMapUnitScale();
1589 }
1590 
1592 {
1593  // <Graphic>
1594  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1595  element.appendChild( graphicElem );
1596 
1597  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
1598 
1599  // <Rotation>
1600  QString angleFunc;
1601  bool ok;
1602  double angle = props.value( "angle", "0" ).toDouble( &ok );
1603  if ( !ok )
1604  {
1605  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1606  }
1607  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1608  {
1609  angleFunc = QString::number( angle + mAngle );
1610  }
1611 
1612  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1613 
1614  // <Displacement>
1616 }
1617 
1619 {
1620  QgsDebugMsg( "Entered." );
1621 
1622  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1623  if ( graphicElem.isNull() )
1624  return nullptr;
1625 
1626  QString path, mimeType;
1627  QColor fillColor;
1628  double size;
1629 
1630  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1631  return nullptr;
1632 
1633  if ( mimeType != "image/svg+xml" )
1634  return nullptr;
1635 
1636  double angle = 0.0;
1637  QString angleFunc;
1638  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1639  {
1640  bool ok;
1641  double d = angleFunc.toDouble( &ok );
1642  if ( ok )
1643  angle = d;
1644  }
1645 
1646  QPointF offset;
1648 
1650  m->setFillColor( fillColor );
1651  //m->setOutlineColor( outlineColor );
1652  //m->setOutlineWidth( outlineWidth );
1653  m->setAngle( angle );
1654  m->setOffset( offset );
1655  return m;
1656 }
1657 
1658 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, 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  {
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)
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
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
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)
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
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) 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.
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)
Flags flags() const
Return combination of flags used for rendering.
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)
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.