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