QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgssymbollayerv2utils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbollayerv2utils.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 "qgssymbollayerv2utils.h"
17 
18 #include "qgssymbollayerv2.h"
20 #include "qgssymbolv2.h"
21 #include "qgsvectorcolorrampv2.h"
22 #include "qgsexpression.h"
23 #include "qgsapplication.h"
24 #include "qgsproject.h"
25 #include "qgsogcutils.h"
26 
27 #include "qgsapplication.h"
28 #include "qgsproject.h"
29 #include "qgslogger.h"
30 #include "qgsrendercontext.h"
31 
32 #include <QColor>
33 #include <QFont>
34 #include <QDomDocument>
35 #include <QDomNode>
36 #include <QDomElement>
37 #include <QIcon>
38 #include <QPainter>
39 #include <QSettings>
40 
41 QString QgsSymbolLayerV2Utils::encodeColor( QColor color )
42 {
43  return QString( "%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
44 }
45 
47 {
48  QStringList lst = str.split( "," );
49  if ( lst.count() < 3 )
50  {
51  return QColor( str );
52  }
53  int red, green, blue, alpha;
54  red = lst[0].toInt();
55  green = lst[1].toInt();
56  blue = lst[2].toInt();
57  alpha = 255;
58  if ( lst.count() > 3 )
59  {
60  alpha = lst[3].toInt();
61  }
62  return QColor( red, green, blue, alpha );
63 }
64 
66 {
67  return QString::number( alpha / 255.0, 'f', 2 );
68 }
69 
71 {
72  bool ok;
73  double alpha = str.toDouble( &ok );
74  if ( !ok || alpha > 1 )
75  alpha = 255;
76  else if ( alpha < 0 )
77  alpha = 0;
78  return alpha * 255;
79 }
80 
81 QString QgsSymbolLayerV2Utils::encodeSldFontStyle( QFont::Style style )
82 {
83  switch ( style )
84  {
85  case QFont::StyleNormal: return "normal";
86  case QFont::StyleItalic: return "italic";
87  case QFont::StyleOblique: return "oblique";
88  default: return "";
89  }
90 }
91 
92 QFont::Style QgsSymbolLayerV2Utils::decodeSldFontStyle( QString str )
93 {
94  if ( str == "normal" ) return QFont::StyleNormal;
95  if ( str == "italic" ) return QFont::StyleItalic;
96  if ( str == "oblique" ) return QFont::StyleOblique;
97  return QFont::StyleNormal;
98 }
99 
101 {
102  if ( weight == 50 ) return "normal";
103  if ( weight == 75 ) return "bold";
104 
105  // QFont::Weight is between 0 and 99
106  // CSS font-weight is between 100 and 900
107  if ( weight < 0 ) return "100";
108  if ( weight > 99 ) return "900";
109  return QString::number( weight * 800 / 99 + 100 );
110 }
111 
113 {
114  bool ok;
115  int weight = str.toInt( &ok );
116  if ( !ok ) return ( int ) QFont::Normal;
117 
118  // CSS font-weight is between 100 and 900
119  // QFont::Weight is between 0 and 99
120  if ( weight > 900 ) return 99;
121  if ( weight < 100 ) return 0;
122  return ( weight - 100 ) * 99 / 800;
123 }
124 
125 QString QgsSymbolLayerV2Utils::encodePenStyle( Qt::PenStyle style )
126 {
127  switch ( style )
128  {
129  case Qt::NoPen: return "no";
130  case Qt::SolidLine: return "solid";
131  case Qt::DashLine: return "dash";
132  case Qt::DotLine: return "dot";
133  case Qt::DashDotLine: return "dash dot";
134  case Qt::DashDotDotLine: return "dash dot dot";
135  default: return "???";
136  }
137 }
138 
139 Qt::PenStyle QgsSymbolLayerV2Utils::decodePenStyle( QString str )
140 {
141  if ( str == "no" ) return Qt::NoPen;
142  if ( str == "solid" ) return Qt::SolidLine;
143  if ( str == "dash" ) return Qt::DashLine;
144  if ( str == "dot" ) return Qt::DotLine;
145  if ( str == "dash dot" ) return Qt::DashDotLine;
146  if ( str == "dash dot dot" ) return Qt::DashDotDotLine;
147  return Qt::SolidLine;
148 }
149 
150 QString QgsSymbolLayerV2Utils::encodePenJoinStyle( Qt::PenJoinStyle style )
151 {
152  switch ( style )
153  {
154  case Qt::BevelJoin: return "bevel";
155  case Qt::MiterJoin: return "miter";
156  case Qt::RoundJoin: return "round";
157  default: return "???";
158  }
159 }
160 
161 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodePenJoinStyle( QString str )
162 {
163  if ( str == "bevel" ) return Qt::BevelJoin;
164  if ( str == "miter" ) return Qt::MiterJoin;
165  if ( str == "round" ) return Qt::RoundJoin;
166  return Qt::BevelJoin;
167 }
168 
169 QString QgsSymbolLayerV2Utils::encodeSldLineJoinStyle( Qt::PenJoinStyle style )
170 {
171  switch ( style )
172  {
173  case Qt::BevelJoin: return "bevel";
174  case Qt::MiterJoin: return "mitre";
175  case Qt::RoundJoin: return "round";
176  default: return "";
177  }
178 }
179 
180 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodeSldLineJoinStyle( QString str )
181 {
182  if ( str == "bevel" ) return Qt::BevelJoin;
183  if ( str == "mitre" ) return Qt::MiterJoin;
184  if ( str == "round" ) return Qt::RoundJoin;
185  return Qt::BevelJoin;
186 }
187 
188 QString QgsSymbolLayerV2Utils::encodePenCapStyle( Qt::PenCapStyle style )
189 {
190  switch ( style )
191  {
192  case Qt::SquareCap: return "square";
193  case Qt::FlatCap: return "flat";
194  case Qt::RoundCap: return "round";
195  default: return "???";
196  }
197 }
198 
199 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodePenCapStyle( QString str )
200 {
201  if ( str == "square" ) return Qt::SquareCap;
202  if ( str == "flat" ) return Qt::FlatCap;
203  if ( str == "round" ) return Qt::RoundCap;
204  return Qt::SquareCap;
205 }
206 
207 QString QgsSymbolLayerV2Utils::encodeSldLineCapStyle( Qt::PenCapStyle style )
208 {
209  switch ( style )
210  {
211  case Qt::SquareCap: return "square";
212  case Qt::FlatCap: return "butt";
213  case Qt::RoundCap: return "round";
214  default: return "";
215  }
216 }
217 
218 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodeSldLineCapStyle( QString str )
219 {
220  if ( str == "square" ) return Qt::SquareCap;
221  if ( str == "butt" ) return Qt::FlatCap;
222  if ( str == "round" ) return Qt::RoundCap;
223  return Qt::SquareCap;
224 }
225 
226 QString QgsSymbolLayerV2Utils::encodeBrushStyle( Qt::BrushStyle style )
227 {
228  switch ( style )
229  {
230  case Qt::SolidPattern : return "solid";
231  case Qt::HorPattern : return "horizontal";
232  case Qt::VerPattern : return "vertical";
233  case Qt::CrossPattern : return "cross";
234  case Qt::BDiagPattern : return "b_diagonal";
235  case Qt::FDiagPattern : return "f_diagonal";
236  case Qt::DiagCrossPattern : return "diagonal_x";
237  case Qt::Dense1Pattern : return "dense1";
238  case Qt::Dense2Pattern : return "dense2";
239  case Qt::Dense3Pattern : return "dense3";
240  case Qt::Dense4Pattern : return "dense4";
241  case Qt::Dense5Pattern : return "dense5";
242  case Qt::Dense6Pattern : return "dense6";
243  case Qt::Dense7Pattern : return "dense7";
244  case Qt::NoBrush : return "no";
245  default: return "???";
246  }
247 }
248 
249 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeBrushStyle( QString str )
250 {
251  if ( str == "solid" ) return Qt::SolidPattern;
252  if ( str == "horizontal" ) return Qt::HorPattern;
253  if ( str == "vertical" ) return Qt::VerPattern;
254  if ( str == "cross" ) return Qt::CrossPattern;
255  if ( str == "b_diagonal" ) return Qt::BDiagPattern;
256  if ( str == "f_diagonal" ) return Qt::FDiagPattern;
257  if ( str == "diagonal_x" ) return Qt::DiagCrossPattern;
258  if ( str == "dense1" ) return Qt::Dense1Pattern;
259  if ( str == "dense2" ) return Qt::Dense2Pattern;
260  if ( str == "dense3" ) return Qt::Dense3Pattern;
261  if ( str == "dense4" ) return Qt::Dense4Pattern;
262  if ( str == "dense5" ) return Qt::Dense5Pattern;
263  if ( str == "dense6" ) return Qt::Dense6Pattern;
264  if ( str == "dense7" ) return Qt::Dense7Pattern;
265  if ( str == "no" ) return Qt::NoBrush;
266  return Qt::SolidPattern;
267 }
268 
269 QString QgsSymbolLayerV2Utils::encodeSldBrushStyle( Qt::BrushStyle style )
270 {
271  switch ( style )
272  {
273  case Qt::CrossPattern: return "cross";
274  case Qt::DiagCrossPattern: return "x";
275 
276  /* The following names are taken from the presentation "GeoServer
277  * Cartographic Rendering" by Andrea Aime at the FOSS4G 2010.
278  * (see http://2010.foss4g.org/presentations/3588.pdf)
279  */
280  case Qt::HorPattern: return "horline";
281  case Qt::VerPattern: return "line";
282  case Qt::BDiagPattern: return "slash";
283  case Qt::FDiagPattern: return "backslash";
284 
285  /* define the other names following the same pattern used above */
286  case Qt::Dense1Pattern:
287  case Qt::Dense2Pattern:
288  case Qt::Dense3Pattern:
289  case Qt::Dense4Pattern:
290  case Qt::Dense5Pattern:
291  case Qt::Dense6Pattern:
292  case Qt::Dense7Pattern:
293  return QString( "brush://%1" ).arg( encodeBrushStyle( style ) );
294 
295  default:
296  return QString();
297  }
298 }
299 
300 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeSldBrushStyle( QString str )
301 {
302  if ( str == "horline" ) return Qt::HorPattern;
303  if ( str == "line" ) return Qt::VerPattern;
304  if ( str == "cross" ) return Qt::CrossPattern;
305  if ( str == "slash" ) return Qt::BDiagPattern;
306  if ( str == "backshash" ) return Qt::FDiagPattern;
307  if ( str == "x" ) return Qt::DiagCrossPattern;
308 
309  if ( str.startsWith( "brush://" ) )
310  return decodeBrushStyle( str.mid( 8 ) );
311 
312  return Qt::NoBrush;
313 }
314 
315 QString QgsSymbolLayerV2Utils::encodePoint( QPointF point )
316 {
317  return QString( "%1,%2" ).arg( point.x() ).arg( point.y() );
318 }
319 
321 {
322  QStringList lst = str.split( ',' );
323  if ( lst.count() != 2 )
324  return QPointF( 0, 0 );
325  return QPointF( lst[0].toDouble(), lst[1].toDouble() );
326 }
327 
329 {
330  switch ( unit )
331  {
332  case QgsSymbolV2::MM:
333  return "MM";
335  return "MapUnit";
336  default:
337  return "MM";
338  }
339 }
340 
342 {
343  if ( str == "MM" )
344  {
345  return QgsSymbolV2::MM;
346  }
347  else if ( str == "MapUnit" )
348  {
349  return QgsSymbolV2::MapUnit;
350  }
351 
352  // millimeters are default
353  return QgsSymbolV2::MM;
354 }
355 
357 {
358  switch ( unit )
359  {
361  if ( scaleFactor )
362  *scaleFactor = 0.001; // from millimeters to meters
363  return "http://www.opengeospatial.org/se/units/metre";
364 
365  case QgsSymbolV2::MM:
366  default:
367  // pixel is the SLD default uom. The "standardized rendering pixel
368  // size" is defined to be 0.28mm × 0.28mm (millimeters).
369  if ( scaleFactor )
370  *scaleFactor = 0.28; // from millimeters to pixels
371 
372  // http://www.opengeospatial.org/sld/units/pixel
373  return QString();
374  }
375 }
376 
378 {
379  if ( str == "http://www.opengeospatial.org/se/units/metre" )
380  {
381  if ( scaleFactor )
382  *scaleFactor = 1000.0; // from meters to millimeters
383  return QgsSymbolV2::MapUnit;
384  }
385  else if ( str == "http://www.opengeospatial.org/se/units/foot" )
386  {
387  if ( scaleFactor )
388  *scaleFactor = 304.8; // from feet to meters
389  return QgsSymbolV2::MapUnit;
390  }
391 
392  // pixel is the SLD default uom. The "standardized rendering pixel
393  // size" is defined to be 0.28mm x 0.28mm (millimeters).
394  if ( scaleFactor )
395  *scaleFactor = 1 / 0.00028; // from pixels to millimeters
396  return QgsSymbolV2::MM;
397 }
398 
399 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
400 {
401  QString vectorString;
402  QVector<qreal>::const_iterator it = v.constBegin();
403  for ( ; it != v.constEnd(); ++it )
404  {
405  if ( it != v.constBegin() )
406  {
407  vectorString.append( ";" );
408  }
409  vectorString.append( QString::number( *it ) );
410  }
411  return vectorString;
412 }
413 
414 QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
415 {
416  QVector<qreal> resultVector;
417 
418  QStringList realList = s.split( ";" );
419  QStringList::const_iterator it = realList.constBegin();
420  for ( ; it != realList.constEnd(); ++it )
421  {
422  resultVector.append( it->toDouble() );
423  }
424 
425  return resultVector;
426 }
427 
428 QString QgsSymbolLayerV2Utils::encodeSldRealVector( const QVector<qreal>& v )
429 {
430  QString vectorString;
431  QVector<qreal>::const_iterator it = v.constBegin();
432  for ( ; it != v.constEnd(); ++it )
433  {
434  if ( it != v.constBegin() )
435  {
436  vectorString.append( " " );
437  }
438  vectorString.append( QString::number( *it ) );
439  }
440  return vectorString;
441 }
442 
443 QVector<qreal> QgsSymbolLayerV2Utils::decodeSldRealVector( const QString& s )
444 {
445  QVector<qreal> resultVector;
446 
447  QStringList realList = s.split( " " );
448  QStringList::const_iterator it = realList.constBegin();
449  for ( ; it != realList.constEnd(); ++it )
450  {
451  resultVector.append( it->toDouble() );
452  }
453 
454  return resultVector;
455 }
456 
458 {
459  QString encodedValue;
460 
461  switch ( scaleMethod )
462  {
464  encodedValue = "diameter";
465  break;
467  encodedValue = "area";
468  break;
469  }
470  return encodedValue;
471 }
472 
474 {
475  QgsSymbolV2::ScaleMethod scaleMethod;
476 
477  if ( str == "diameter" )
478  {
479  scaleMethod = QgsSymbolV2::ScaleDiameter;
480  }
481  else
482  {
483  scaleMethod = QgsSymbolV2::ScaleArea;
484  }
485 
486  return scaleMethod;
487 }
488 
490 {
491  return QIcon( symbolPreviewPixmap( symbol, size ) );
492 }
493 
495 {
496  Q_ASSERT( symbol );
497 
498  QPixmap pixmap( size );
499  pixmap.fill( Qt::transparent );
500  QPainter painter;
501  painter.begin( &pixmap );
502  painter.setRenderHint( QPainter::Antialiasing );
503  symbol->drawPreviewIcon( &painter, size );
504  painter.end();
505  return pixmap;
506 }
507 
509 {
510  double maxBleed = 0;
511  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
512  {
513  QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
514  double layerMaxBleed = layer->estimateMaxBleed();
515  maxBleed = layerMaxBleed > maxBleed ? layerMaxBleed : maxBleed;
516  }
517 
518  return maxBleed;
519 }
520 
522 {
523  QPixmap pixmap( size );
524  pixmap.fill( Qt::transparent );
525  QPainter painter;
526  painter.begin( &pixmap );
527  painter.setRenderHint( QPainter::Antialiasing );
528  QgsRenderContext renderContext = createRenderContext( &painter );
529  QgsSymbolV2RenderContext symbolContext( renderContext, u );
530  layer->drawPreviewIcon( symbolContext, size );
531  painter.end();
532  return QIcon( pixmap );
533 }
534 
536 {
537  return QIcon( colorRampPreviewPixmap( ramp, size ) );
538 }
539 
541 {
542  QPixmap pixmap( size );
543  pixmap.fill( Qt::transparent );
544  // pixmap.fill( Qt::white ); // this makes the background white instead of transparent
545  QPainter painter;
546  painter.begin( &pixmap );
547 
548  //draw stippled background, for transparent images
549  drawStippledBackround( &painter, QRect( 0, 0, size.width(), size.height() ) );
550 
551  // antialising makes the colors duller, and no point in antialiasing a color ramp
552  // painter.setRenderHint( QPainter::Antialiasing );
553  for ( int i = 0; i < size.width(); i++ )
554  {
555  QPen pen( ramp->color(( double ) i / size.width() ) );
556  painter.setPen( pen );
557  painter.drawLine( i, 0, i, size.height() - 1 );
558  }
559  painter.end();
560  return pixmap;
561 }
562 
563 void QgsSymbolLayerV2Utils::drawStippledBackround( QPainter* painter, QRect rect )
564 {
565  // create a 2x2 checker-board image
566  uchar pixDataRGB[] = { 255, 255, 255, 255,
567  127, 127, 127, 255,
568  127, 127, 127, 255,
569  255, 255, 255, 255
570  };
571  QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
572  // scale it to rect so at least 5 patterns are shown
573  int width = ( rect.width() < rect.height() ) ?
574  rect.width() / 2.5 : rect.height() / 2.5;
575  QPixmap pix = QPixmap::fromImage( img.scaled( width, width ) );
576  // fill rect with texture
577  QBrush brush;
578  brush.setTexture( pix );
579  painter->fillRect( rect, brush );
580 }
581 
582 #include <QPolygonF>
583 
584 #include <cmath>
585 #include <cfloat>
586 
587 
588 #if !defined(GEOS_VERSION_MAJOR) || !defined(GEOS_VERSION_MINOR) || \
589  ((GEOS_VERSION_MAJOR<3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR<3)))
590 // calculate line's angle and tangent
591 static bool lineInfo( QPointF p1, QPointF p2, double& angle, double& t )
592 {
593  double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();
594 
595  if ( x1 == x2 && y1 == y2 )
596  return false;
597 
598  // tangent
599  t = ( x1 == x2 ? DBL_MAX : ( y2 - y1 ) / ( x2 - x1 ) );
600 
601  // angle
602  if ( t == DBL_MAX )
603  angle = ( y2 > y1 ? M_PI / 2 : M_PI * 3 / 2 ); // angle is 90 or 270
604  else if ( t == 0 )
605  angle = ( x2 > x1 ? 0 : M_PI ); // angle is 0 or 180
606  else if ( t >= 0 )
607  angle = ( y2 > y1 ? atan( t ) : M_PI + atan( t ) );
608  else // t < 0
609  angle = ( y2 > y1 ? M_PI + atan( t ) : atan( t ) );
610 
611  return true;
612 }
613 
614 // offset a point with an angle and distance
615 static QPointF offsetPoint( QPointF pt, double angle, double dist )
616 {
617  return QPointF( pt.x() + dist * cos( angle ), pt.y() + dist * sin( angle ) );
618 }
619 
620 // calc intersection of two (infinite) lines defined by one point and tangent
621 static QPointF linesIntersection( QPointF p1, double t1, QPointF p2, double t2 )
622 {
623  // parallel lines? (or the difference between angles is less than appr. 10 degree)
624  if (( t1 == DBL_MAX && t2 == DBL_MAX ) || qAbs( atan( t1 ) - atan( t2 ) ) < 0.175 )
625  return QPointF();
626 
627  double x, y;
628  if ( t1 == DBL_MAX || t2 == DBL_MAX )
629  {
630  // in case one line is with angle 90 resp. 270 degrees (tangent undefined)
631  // swap them so that line 2 is with undefined tangent
632  if ( t1 == DBL_MAX )
633  {
634  QPointF pSwp = p1; p1 = p2; p2 = pSwp;
635  double tSwp = t1; t1 = t2; t2 = tSwp;
636  }
637 
638  x = p2.x();
639  }
640  else
641  {
642  // usual case
643  x = (( p1.y() - p2.y() ) + t2 * p2.x() - t1 * p1.x() ) / ( t2 - t1 );
644  }
645 
646  y = p1.y() + t1 * ( x - p1.x() );
647  return QPointF( x, y );
648 }
649 #endif
650 
651 
652 QPolygonF offsetLine( QPolygonF polyline, double dist )
653 {
654  if ( polyline.count() < 2 )
655  return polyline;
656 
657  QPolygonF newLine;
658 
659  // need at least geos 3.3 for OffsetCurve tool
660 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
661  ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3)))
662 
663  unsigned int i, pointCount = polyline.count();
664 
665  QgsPolyline tempPolyline( pointCount );
666  QPointF* tempPtr = polyline.data();
667  for ( i = 0; i < pointCount; ++i, tempPtr++ ) tempPolyline[i] = QgsPoint( tempPtr->rx(), tempPtr->ry() );
668 
669  QgsGeometry* tempGeometry = QgsGeometry::fromPolyline( tempPolyline );
670  if ( tempGeometry )
671  {
672  const GEOSGeometry* geosGeom = tempGeometry->asGeos();
673  GEOSGeometry* offsetGeom = GEOSOffsetCurve( geosGeom, dist, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ );
674 
675  if ( offsetGeom )
676  {
677  tempGeometry->fromGeos( offsetGeom );
678  tempPolyline = tempGeometry->asPolyline();
679 
680  pointCount = tempPolyline.count();
681  newLine.resize( pointCount );
682 
683  QgsPoint* tempPtr2 = tempPolyline.data();
684  for ( i = 0; i < pointCount; ++i, tempPtr2++ ) newLine[i] = QPointF( tempPtr2->x(), tempPtr2->y() );
685 
686  delete tempGeometry;
687  return newLine;
688  }
689  delete tempGeometry;
690  }
691 
692  // returns original polyline when 'GEOSOffsetCurve' fails!
693  return polyline;
694 
695 #else
696 
697  double angle = 0.0, t_new, t_old = 0;
698  QPointF pt_old, pt_new;
699  QPointF p1 = polyline[0], p2;
700  bool first_point = true;
701 
702  for ( int i = 1; i < polyline.count(); i++ )
703  {
704  p2 = polyline[i];
705 
706  if ( !lineInfo( p1, p2, angle, t_new ) )
707  continue; // not a line...
708 
709  pt_new = offsetPoint( p1, angle + M_PI / 2, dist );
710 
711  if ( ! first_point )
712  {
713  // if it's not the first line segment
714  // calc intersection with last line (with offset)
715  QPointF pt_tmp = linesIntersection( pt_old, t_old, pt_new, t_new );
716  if ( !pt_tmp.isNull() )
717  pt_new = pt_tmp;
718  }
719 
720  newLine.append( pt_new );
721 
722  pt_old = pt_new;
723  t_old = t_new;
724  p1 = p2;
725  first_point = false;
726  }
727 
728  // last line segment:
729  pt_new = offsetPoint( p2, angle + M_PI / 2, dist );
730  newLine.append( pt_new );
731  return newLine;
732 
733 #endif
734 }
735 
737 
738 
740 {
741  QgsSymbolLayerV2List layers;
742  QDomNode layerNode = element.firstChild();
743 
744  while ( !layerNode.isNull() )
745  {
746  QDomElement e = layerNode.toElement();
747  if ( !e.isNull() )
748  {
749  if ( e.tagName() != "layer" )
750  {
751  QgsDebugMsg( "unknown tag " + e.tagName() );
752  }
753  else
754  {
755  QgsSymbolLayerV2* layer = loadSymbolLayer( e );
756 
757  if ( layer != NULL )
758  {
759  // Dealing with sub-symbols nested into a layer
760  QDomElement s = e.firstChildElement( "symbol" );
761  if ( !s.isNull() )
762  {
763  QgsSymbolV2* subSymbol = loadSymbol( s );
764  bool res = layer->setSubSymbol( subSymbol );
765  if ( !res )
766  {
767  QgsDebugMsg( "symbol layer refused subsymbol: " + s.attribute( "name" ) );
768  }
769  }
770  layers.append( layer );
771  }
772  }
773  }
774  layerNode = layerNode.nextSibling();
775  }
776 
777  if ( layers.count() == 0 )
778  {
779  QgsDebugMsg( "no layers for symbol" );
780  return NULL;
781  }
782 
783  QString symbolType = element.attribute( "type" );
784 
785  QgsSymbolV2* symbol = 0;
786  if ( symbolType == "line" )
787  symbol = new QgsLineSymbolV2( layers );
788  else if ( symbolType == "fill" )
789  symbol = new QgsFillSymbolV2( layers );
790  else if ( symbolType == "marker" )
791  symbol = new QgsMarkerSymbolV2( layers );
792  else
793  {
794  QgsDebugMsg( "unknown symbol type " + symbolType );
795  return NULL;
796  }
797 
798  if ( element.hasAttribute( "outputUnit" ) )
799  {
800  symbol->setOutputUnit( decodeOutputUnit( element.attribute( "outputUnit" ) ) );
801  }
802  symbol->setAlpha( element.attribute( "alpha", "1.0" ).toDouble() );
803 
804  return symbol;
805 }
806 
808 {
809  QString layerClass = element.attribute( "class" );
810  bool locked = element.attribute( "locked" ).toInt();
811  int pass = element.attribute( "pass" ).toInt();
812 
813  // parse properties
814  QgsStringMap props = parseProperties( element );
815 
816  QgsSymbolLayerV2* layer;
817  layer = QgsSymbolLayerV2Registry::instance()->createSymbolLayer( layerClass, props );
818  if ( layer )
819  {
820  layer->setLocked( locked );
821  layer->setRenderingPass( pass );
822  return layer;
823  }
824  else
825  {
826  QgsDebugMsg( "unknown class " + layerClass );
827  return NULL;
828  }
829 }
830 
832 {
833  switch ( type )
834  {
835  case QgsSymbolV2::Line: return "line";
836  case QgsSymbolV2::Marker: return "marker";
837  case QgsSymbolV2::Fill: return "fill";
838  default: return "";
839  }
840 }
841 
842 QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc )
843 {
844  Q_ASSERT( symbol );
845  QDomElement symEl = doc.createElement( "symbol" );
846  symEl.setAttribute( "type", _nameForSymbolType( symbol->type() ) );
847  symEl.setAttribute( "name", name );
848  symEl.setAttribute( "alpha", QString::number( symbol->alpha() ) );
849  QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
850 
851  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
852  {
853  QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
854 
855  QDomElement layerEl = doc.createElement( "layer" );
856  layerEl.setAttribute( "class", layer->layerType() );
857  layerEl.setAttribute( "locked", layer->isLocked() );
858  layerEl.setAttribute( "pass", layer->renderingPass() );
859  saveProperties( layer->properties(), doc, layerEl );
860  if ( layer->subSymbol() != NULL )
861  {
862  QString subname = QString( "@%1@%2" ).arg( name ).arg( i );
863  QDomElement subEl = saveSymbol( subname, layer->subSymbol(), doc );
864  layerEl.appendChild( subEl );
865  }
866  symEl.appendChild( layerEl );
867  }
868 
869  return symEl;
870 }
871 
872 
874  QGis::GeometryType geomType,
875  QgsSymbolLayerV2List &layers )
876 {
877  QgsDebugMsg( "Entered." );
878 
879  if ( element.isNull() )
880  return false;
881 
882  QgsSymbolLayerV2 *l = 0;
883 
884  QString symbolizerName = element.localName();
885 
886  if ( symbolizerName == "PointSymbolizer" )
887  {
888  // first check for Graphic element, nothing will be rendered if not found
889  QDomElement graphicElem = element.firstChildElement( "Graphic" );
890  if ( graphicElem.isNull() )
891  {
892  QgsDebugMsg( "Graphic element not found in PointSymbolizer" );
893  }
894  else
895  {
896  switch ( geomType )
897  {
898  case QGis::Polygon:
899  // polygon layer and point symbolizer: draw poligon centroid
900  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "CentroidFill", element );
901  if ( l )
902  layers.append( l );
903 
904  break;
905 
906  case QGis::Point:
907  // point layer and point symbolizer: use markers
908  l = createMarkerLayerFromSld( element );
909  if ( l )
910  layers.append( l );
911 
912  break;
913 
914  case QGis::Line:
915  // line layer and point symbolizer: draw central point
916  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
917  if ( l )
918  layers.append( l );
919 
920  break;
921 
922  default:
923  break;
924  }
925  }
926  }
927 
928  if ( symbolizerName == "LineSymbolizer" )
929  {
930  // check for Stroke element, nothing will be rendered if not found
931  QDomElement strokeElem = element.firstChildElement( "Stroke" );
932  if ( strokeElem.isNull() )
933  {
934  QgsDebugMsg( "Stroke element not found in LineSymbolizer" );
935  }
936  else
937  {
938  switch ( geomType )
939  {
940  case QGis::Polygon:
941  case QGis::Line:
942  // polygon layer and line symbolizer: draw polygon outline
943  // line layer and line symbolizer: draw line
944  l = createLineLayerFromSld( element );
945  if ( l )
946  layers.append( l );
947 
948  break;
949 
950  case QGis::Point:
951  // point layer and line symbolizer: draw a little line marker
952  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
953  if ( l )
954  layers.append( l );
955 
956  default:
957  break;
958  }
959  }
960  }
961 
962  if ( symbolizerName == "PolygonSymbolizer" )
963  {
964  // get Fill and Stroke elements, nothing will be rendered if both are missing
965  QDomElement fillElem = element.firstChildElement( "Fill" );
966  QDomElement strokeElem = element.firstChildElement( "Stroke" );
967  if ( fillElem.isNull() && strokeElem.isNull() )
968  {
969  QgsDebugMsg( "neither Fill nor Stroke element not found in PolygonSymbolizer" );
970  }
971  else
972  {
973  QgsSymbolLayerV2 *l = 0;
974 
975  switch ( geomType )
976  {
977  case QGis::Polygon:
978  // polygon layer and polygon symbolizer: draw fill
979 
980  l = createFillLayerFromSld( element );
981  if ( l )
982  {
983  layers.append( l );
984 
985  // SVGFill and SimpleFill symbolLayerV2 supports outline internally,
986  // so don't go forward to create a different symbolLayerV2 for outline
987  if ( l->layerType() == "SimpleFill" || l->layerType() == "SVGFill" )
988  break;
989  }
990 
991  // now create polygon outline
992  // polygon layer and polygon symbolizer: draw polygon outline
993  l = createLineLayerFromSld( element );
994  if ( l )
995  layers.append( l );
996 
997  break;
998 
999  case QGis::Line:
1000  // line layer and polygon symbolizer: draw line
1001  l = createLineLayerFromSld( element );
1002  if ( l )
1003  layers.append( l );
1004 
1005  break;
1006 
1007  case QGis::Point:
1008  // point layer and polygon symbolizer: draw a square marker
1009  convertPolygonSymbolizerToPointMarker( element, layers );
1010  break;
1011 
1012  default:
1013  break;
1014  }
1015  }
1016  }
1017 
1018  return true;
1019 }
1020 
1022 {
1023  QDomElement fillElem = element.firstChildElement( "Fill" );
1024  if ( fillElem.isNull() )
1025  {
1026  QgsDebugMsg( "Fill element not found" );
1027  return NULL;
1028  }
1029 
1030  QgsSymbolLayerV2 *l = 0;
1031 
1032  if ( needLinePatternFill( element ) )
1033  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "LinePatternFill", element );
1034  else if ( needPointPatternFill( element ) )
1035  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "PointPatternFill", element );
1036  else if ( needSvgFill( element ) )
1037  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SVGFill", element );
1038  else
1039  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleFill", element );
1040 
1041  return l;
1042 }
1043 
1045 {
1046  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1047  if ( strokeElem.isNull() )
1048  {
1049  QgsDebugMsg( "Stroke element not found" );
1050  return NULL;
1051  }
1052 
1053  QgsSymbolLayerV2 *l = 0;
1054 
1055  if ( needMarkerLine( element ) )
1056  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
1057  else
1058  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleLine", element );
1059 
1060  return l;
1061 }
1062 
1064 {
1065  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1066  if ( graphicElem.isNull() )
1067  {
1068  QgsDebugMsg( "Graphic element not found" );
1069  return NULL;
1070  }
1071 
1072  QgsSymbolLayerV2 *l = 0;
1073 
1074  if ( needFontMarker( element ) )
1075  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "FontMarker", element );
1076  else if ( needSvgMarker( element ) )
1077  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SvgMarker", element );
1078  else if ( needEllipseMarker( element ) )
1079  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "EllipseMarker", element );
1080  else
1081  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
1082 
1083  return l;
1084 }
1085 
1086 bool QgsSymbolLayerV2Utils::hasExternalGraphic( QDomElement &element )
1087 {
1088  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1089  if ( graphicElem.isNull() )
1090  return false;
1091 
1092  QDomElement externalGraphicElem = graphicElem.firstChildElement( "ExternalGraphic" );
1093  if ( externalGraphicElem.isNull() )
1094  return false;
1095 
1096  // check for format
1097  QDomElement formatElem = externalGraphicElem.firstChildElement( "Format" );
1098  if ( formatElem.isNull() )
1099  return false;
1100 
1101  QString format = formatElem.firstChild().nodeValue();
1102  if ( format != "image/svg+xml" )
1103  {
1104  QgsDebugMsg( "unsupported External Graphic format found: " + format );
1105  return false;
1106  }
1107 
1108  // check for a valid content
1109  QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( "OnlineResource" );
1110  QDomElement inlineContentElem = externalGraphicElem.firstChildElement( "InlineContent" );
1111  if ( !onlineResourceElem.isNull() )
1112  {
1113  return true;
1114  }
1115 #if 0
1116  else if ( !inlineContentElem.isNull() )
1117  {
1118  return false; // not implemented yet
1119  }
1120 #endif
1121  else
1122  {
1123  return false;
1124  }
1125 }
1126 
1127 bool QgsSymbolLayerV2Utils::hasWellKnownMark( QDomElement &element )
1128 {
1129  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1130  if ( graphicElem.isNull() )
1131  return false;
1132 
1133  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
1134  if ( markElem.isNull() )
1135  return false;
1136 
1137  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
1138  if ( wellKnownNameElem.isNull() )
1139  return false;
1140 
1141  return true;
1142 }
1143 
1144 
1145 bool QgsSymbolLayerV2Utils::needFontMarker( QDomElement &element )
1146 {
1147  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1148  if ( graphicElem.isNull() )
1149  return false;
1150 
1151  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
1152  if ( markElem.isNull() )
1153  return false;
1154 
1155  // check for format
1156  QDomElement formatElem = markElem.firstChildElement( "Format" );
1157  if ( formatElem.isNull() )
1158  return false;
1159 
1160  QString format = formatElem.firstChild().nodeValue();
1161  if ( format != "ttf" )
1162  {
1163  QgsDebugMsg( "unsupported Graphic Mark format found: " + format );
1164  return false;
1165  }
1166 
1167  // check for a valid content
1168  QDomElement onlineResourceElem = markElem.firstChildElement( "OnlineResource" );
1169  QDomElement inlineContentElem = markElem.firstChildElement( "InlineContent" );
1170  if ( !onlineResourceElem.isNull() )
1171  {
1172  // mark with ttf format has a markIndex element
1173  QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
1174  if ( !markIndexElem.isNull() )
1175  return true;
1176  }
1177  else if ( !inlineContentElem.isNull() )
1178  {
1179  return false; // not implemented yet
1180  }
1181 
1182  return false;
1183 }
1184 
1185 bool QgsSymbolLayerV2Utils::needSvgMarker( QDomElement &element )
1186 {
1187  return hasExternalGraphic( element );
1188 }
1189 
1190 bool QgsSymbolLayerV2Utils::needEllipseMarker( QDomElement &element )
1191 {
1192  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1193  if ( graphicElem.isNull() )
1194  return false;
1195 
1196  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
1197  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1198  {
1199  if ( it.key() == "widthHeightFactor" )
1200  {
1201  return true;
1202  }
1203  }
1204 
1205  return false;
1206 }
1207 
1208 bool QgsSymbolLayerV2Utils::needMarkerLine( QDomElement &element )
1209 {
1210  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1211  if ( strokeElem.isNull() )
1212  return false;
1213 
1214  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1215  if ( graphicStrokeElem.isNull() )
1216  return false;
1217 
1218  return hasWellKnownMark( graphicStrokeElem );
1219 }
1220 
1222 {
1223  QDomElement fillElem = element.firstChildElement( "Fill" );
1224  if ( fillElem.isNull() )
1225  return false;
1226 
1227  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1228  if ( graphicFillElem.isNull() )
1229  return false;
1230 
1231  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1232  if ( graphicElem.isNull() )
1233  return false;
1234 
1235  // line pattern fill uses horline wellknown marker with an angle
1236 
1237  QString name;
1238  QColor fillColor, borderColor;
1239  double size, borderWidth;
1240  Qt::PenStyle borderStyle;
1241  if ( !wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
1242  return false;
1243 
1244  if ( name != "horline" )
1245  return false;
1246 
1247  QString angleFunc;
1248  if ( !rotationFromSldElement( graphicElem, angleFunc ) )
1249  return false;
1250 
1251  bool ok;
1252  double angle = angleFunc.toDouble( &ok );
1253  if ( !ok || angle == 0 )
1254  return false;
1255 
1256  return true;
1257 }
1258 
1260 {
1261  Q_UNUSED( element );
1262  return false;
1263 }
1264 
1265 bool QgsSymbolLayerV2Utils::needSvgFill( QDomElement &element )
1266 {
1267  QDomElement fillElem = element.firstChildElement( "Fill" );
1268  if ( fillElem.isNull() )
1269  return false;
1270 
1271  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1272  if ( graphicFillElem.isNull() )
1273  return false;
1274 
1275  return hasExternalGraphic( graphicFillElem );
1276 }
1277 
1278 
1280 {
1281  QgsDebugMsg( "Entered." );
1282 
1283  /* SE 1.1 says about PolygonSymbolizer:
1284  if a point geometry is referenced instead of a polygon,
1285  then a small, square, ortho-normal polygon should be
1286  constructed for rendering.
1287  */
1288 
1289  QgsSymbolLayerV2List layers;
1290 
1291  // retrieve both Fill and Stroke elements
1292  QDomElement fillElem = element.firstChildElement( "Fill" );
1293  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1294 
1295  // first symbol layer
1296  {
1297  bool validFill = false, validBorder = false;
1298 
1299  // check for simple fill
1300  // Fill element can contain some SvgParameter elements
1301  QColor fillColor;
1302  Qt::BrushStyle fillStyle;
1303 
1304  if ( fillFromSld( fillElem, fillStyle, fillColor ) )
1305  validFill = true;
1306 
1307  // check for simple outline
1308  // Stroke element can contain some SvgParameter elements
1309  QColor borderColor;
1310  Qt::PenStyle borderStyle;
1311  double borderWidth = 1.0, dashOffset = 0.0;
1312  QVector<qreal> customDashPattern;
1313 
1314  if ( lineFromSld( strokeElem, borderStyle, borderColor, borderWidth,
1315  0, 0, &customDashPattern, &dashOffset ) )
1316  validBorder = true;
1317 
1318  if ( validFill || validBorder )
1319  {
1320  QgsStringMap map;
1321  map["name"] = "square";
1322  map["color"] = encodeColor( validFill ? fillColor : Qt::transparent );
1323  map["color_border"] = encodeColor( validBorder ? borderColor : Qt::transparent );
1324  map["size"] = QString::number( 6 );
1325  map["angle"] = QString::number( 0 );
1326  map["offset"] = encodePoint( QPointF( 0, 0 ) );
1327  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SimpleMarker", map ) );
1328  }
1329  }
1330 
1331  // second symbol layer
1332  {
1333  bool validFill = false, validBorder = false;
1334 
1335  // check for graphic fill
1336  QString name, format;
1337  int markIndex = -1;
1338  QColor fillColor, borderColor;
1339  double borderWidth = 1.0, size = 0.0, angle = 0.0;
1340  QPointF anchor, offset;
1341 
1342  // Fill element can contain a GraphicFill element
1343  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1344  if ( !graphicFillElem.isNull() )
1345  {
1346  // GraphicFill element must contain a Graphic element
1347  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1348  if ( !graphicElem.isNull() )
1349  {
1350  // Graphic element can contains some ExternalGraphic and Mark element
1351  // search for the first supported one and use it
1352  bool found = false;
1353 
1354  QDomElement graphicChildElem = graphicElem.firstChildElement();
1355  while ( !graphicChildElem.isNull() )
1356  {
1357  if ( graphicChildElem.localName() == "Mark" )
1358  {
1359  // check for a well known name
1360  QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( "WellKnownName" );
1361  if ( !wellKnownNameElem.isNull() )
1362  {
1363  name = wellKnownNameElem.firstChild().nodeValue();
1364  found = true;
1365  break;
1366  }
1367  }
1368 
1369  if ( graphicChildElem.localName() == "ExternalGraphic" || graphicChildElem.localName() == "Mark" )
1370  {
1371  // check for external graphic format
1372  QDomElement formatElem = graphicChildElem.firstChildElement( "Format" );
1373  if ( formatElem.isNull() )
1374  continue;
1375 
1376  format = formatElem.firstChild().nodeValue();
1377 
1378  // TODO: remove this check when more formats will be supported
1379  // only SVG external graphics are supported in this moment
1380  if ( graphicChildElem.localName() == "ExternalGraphic" && format != "image/svg+xml" )
1381  continue;
1382 
1383  // TODO: remove this check when more formats will be supported
1384  // only ttf marks are supported in this moment
1385  if ( graphicChildElem.localName() == "Mark" && format != "ttf" )
1386  continue;
1387 
1388  // check for a valid content
1389  QDomElement onlineResourceElem = graphicChildElem.firstChildElement( "OnlineResource" );
1390  QDomElement inlineContentElem = graphicChildElem.firstChildElement( "InlineContent" );
1391 
1392  if ( !onlineResourceElem.isNull() )
1393  {
1394  name = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
1395 
1396  if ( graphicChildElem.localName() == "Mark" && format == "ttf" )
1397  {
1398  // mark with ttf format may have a name like ttf://fontFamily
1399  if ( name.startsWith( "ttf://" ) )
1400  name = name.mid( 6 );
1401 
1402  // mark with ttf format has a markIndex element
1403  QDomElement markIndexElem = graphicChildElem.firstChildElement( "MarkIndex" );
1404  if ( markIndexElem.isNull() )
1405  continue;
1406 
1407  bool ok;
1408  int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
1409  if ( !ok || v < 0 )
1410  continue;
1411 
1412  markIndex = v;
1413  }
1414 
1415  found = true;
1416  break;
1417  }
1418 #if 0
1419  else if ( !inlineContentElem.isNull() )
1420  continue; // TODO: not implemented yet
1421 #endif
1422  else
1423  continue;
1424  }
1425 
1426  // if Mark element is present but it doesn't contains neither
1427  // WellKnownName nor OnlineResource nor InlineContent,
1428  // use the default mark (square)
1429  if ( graphicChildElem.localName() == "Mark" )
1430  {
1431  name = "square";
1432  found = true;
1433  break;
1434  }
1435  }
1436 
1437  // if found a valid Mark, check for its Fill and Stroke element
1438  if ( found && graphicChildElem.localName() == "Mark" )
1439  {
1440  // XXX: recursive definition!?! couldn't be dangerous???
1441  // to avoid recursion we handle only simple fill and simple stroke
1442 
1443  // check for simple fill
1444  // Fill element can contain some SvgParameter elements
1445  Qt::BrushStyle markFillStyle;
1446 
1447  QDomElement markFillElem = graphicChildElem.firstChildElement( "Fill" );
1448  if ( fillFromSld( markFillElem, markFillStyle, fillColor ) )
1449  validFill = true;
1450 
1451  // check for simple outline
1452  // Stroke element can contain some SvgParameter elements
1453  Qt::PenStyle borderStyle;
1454  double borderWidth = 1.0, dashOffset = 0.0;
1455  QVector<qreal> customDashPattern;
1456 
1457  QDomElement markStrokeElem = graphicChildElem.firstChildElement( "Stroke" );
1458  if ( lineFromSld( markStrokeElem, borderStyle, borderColor, borderWidth,
1459  0, 0, &customDashPattern, &dashOffset ) )
1460  validBorder = true;
1461  }
1462 
1463  if ( found )
1464  {
1465  // check for Opacity, Size, Rotation, AnchorPoint, Displacement
1466  QDomElement opacityElem = graphicElem.firstChildElement( "Opacity" );
1467  if ( !opacityElem.isNull() )
1468  fillColor.setAlpha( decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
1469 
1470  QDomElement sizeElem = graphicElem.firstChildElement( "Size" );
1471  if ( !sizeElem.isNull() )
1472  {
1473  bool ok;
1474  double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
1475  if ( ok && v > 0 )
1476  size = v;
1477  }
1478 
1479  QString angleFunc;
1480  if ( rotationFromSldElement( graphicElem, angleFunc ) && !angleFunc.isEmpty() )
1481  {
1482  bool ok;
1483  double v = angleFunc.toDouble( &ok );
1484  if ( ok )
1485  angle = v;
1486  }
1487 
1488  displacementFromSldElement( graphicElem, offset );
1489  }
1490  }
1491  }
1492 
1493  if ( validFill || validBorder )
1494  {
1495  if ( format == "image/svg+xml" )
1496  {
1497  QgsStringMap map;
1498  map["name"] = name;
1499  map["fill"] = fillColor.name();
1500  map["outline"] = borderColor.name();
1501  map["outline-width"] = QString::number( borderWidth );
1502  if ( !qgsDoubleNear( size, 0.0 ) )
1503  map["size"] = QString::number( size );
1504  if ( !qgsDoubleNear( angle, 0.0 ) )
1505  map["angle"] = QString::number( angle );
1506  if ( !offset.isNull() )
1507  map["offset"] = encodePoint( offset );
1508  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SvgMarker", map ) );
1509  }
1510  else if ( format == "ttf" )
1511  {
1512  QgsStringMap map;
1513  map["font"] = name;
1514  map["chr"] = markIndex;
1515  map["color"] = encodeColor( validFill ? fillColor : Qt::transparent );
1516  if ( size > 0 )
1517  map["size"] = QString::number( size );
1518  if ( !qgsDoubleNear( angle, 0.0 ) )
1519  map["angle"] = QString::number( angle );
1520  if ( !offset.isNull() )
1521  map["offset"] = encodePoint( offset );
1522  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "FontMarker", map ) );
1523  }
1524  }
1525  }
1526 
1527  if ( layers.isEmpty() )
1528  return false;
1529 
1530  layerList << layers;
1531  layers.clear();
1532  return true;
1533 }
1534 
1535 void QgsSymbolLayerV2Utils::fillToSld( QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color )
1536 {
1537  QString patternName;
1538  switch ( brushStyle )
1539  {
1540  case Qt::NoBrush:
1541  return;
1542 
1543  case Qt::SolidPattern:
1544  if ( color.isValid() )
1545  {
1546  element.appendChild( createSvgParameterElement( doc, "fill", color.name() ) );
1547  if ( color.alpha() < 255 )
1548  element.appendChild( createSvgParameterElement( doc, "fill-opacity", encodeSldAlpha( color.alpha() ) ) );
1549  }
1550  return;
1551 
1552  case Qt::CrossPattern:
1553  case Qt::DiagCrossPattern:
1554  case Qt::HorPattern:
1555  case Qt::VerPattern:
1556  case Qt::BDiagPattern:
1557  case Qt::FDiagPattern:
1558  case Qt::Dense1Pattern:
1559  case Qt::Dense2Pattern:
1560  case Qt::Dense3Pattern:
1561  case Qt::Dense4Pattern:
1562  case Qt::Dense5Pattern:
1563  case Qt::Dense6Pattern:
1564  case Qt::Dense7Pattern:
1565  patternName = encodeSldBrushStyle( brushStyle );
1566  break;
1567 
1568  default:
1569  element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
1570  return;
1571  }
1572 
1573  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
1574  element.appendChild( graphicFillElem );
1575 
1576  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1577  graphicFillElem.appendChild( graphicElem );
1578 
1579  QColor fillColor = patternName.startsWith( "brush://" ) ? color : QColor();
1580  QColor borderColor = !patternName.startsWith( "brush://" ) ? color : QColor();
1581 
1582  /* Use WellKnownName tag to handle QT brush styles. */
1583  wellKnownMarkerToSld( doc, graphicElem, patternName, fillColor, borderColor, Qt::SolidLine, -1, -1 );
1584 }
1585 
1586 bool QgsSymbolLayerV2Utils::fillFromSld( QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color )
1587 {
1588  QgsDebugMsg( "Entered." );
1589 
1590  brushStyle = Qt::SolidPattern;
1591  color = QColor( "#808080" );
1592 
1593  if ( element.isNull() )
1594  {
1595  brushStyle = Qt::NoBrush;
1596  color = QColor();
1597  return true;
1598  }
1599 
1600  QDomElement graphicFillElem = element.firstChildElement( "GraphicFill" );
1601  // if no GraphicFill element is found, it's a solid fill
1602  if ( graphicFillElem.isNull() )
1603  {
1604  QgsStringMap svgParams = getSvgParameterList( element );
1605  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
1606  {
1607  QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
1608 
1609  if ( it.key() == "fill" )
1610  color = QColor( it.value() );
1611  else if ( it.key() == "fill-opacity" )
1612  color.setAlpha( decodeSldAlpha( it.value() ) );
1613  }
1614  }
1615  else // wellKnown marker
1616  {
1617  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1618  if ( graphicElem.isNull() )
1619  return false; // Graphic is required within GraphicFill
1620 
1621  QString patternName = "square";
1622  QColor fillColor, borderColor;
1623  double borderWidth, size;
1624  Qt::PenStyle borderStyle;
1625  if ( !wellKnownMarkerFromSld( graphicElem, patternName, fillColor, borderColor, borderStyle, borderWidth, size ) )
1626  return false;
1627 
1628  brushStyle = decodeSldBrushStyle( patternName );
1629  if ( brushStyle == Qt::NoBrush )
1630  return false; // unable to decode brush style
1631 
1632  QColor c = patternName.startsWith( "brush://" ) ? fillColor : borderColor;
1633  if ( c.isValid() )
1634  color = c;
1635  }
1636 
1637  return true;
1638 }
1639 
1640 void QgsSymbolLayerV2Utils::lineToSld( QDomDocument &doc, QDomElement &element,
1641  Qt::PenStyle penStyle, QColor color, double width,
1642  const Qt::PenJoinStyle *penJoinStyle, const Qt::PenCapStyle *penCapStyle,
1643  const QVector<qreal> *customDashPattern, double dashOffset )
1644 {
1645  QVector<qreal> dashPattern;
1646  const QVector<qreal> *pattern = &dashPattern;
1647 
1648  if ( penStyle == Qt::CustomDashLine && !customDashPattern )
1649  {
1650  element.appendChild( doc.createComment( "WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) );
1651  penStyle = Qt::DashLine;
1652  }
1653 
1654  switch ( penStyle )
1655  {
1656  case Qt::NoPen:
1657  return;
1658 
1659  case Qt::SolidLine:
1660  break;
1661 
1662  case Qt::DashLine:
1663  dashPattern.push_back( 4.0 );
1664  dashPattern.push_back( 2.0 );
1665  break;
1666  case Qt::DotLine:
1667  dashPattern.push_back( 1.0 );
1668  dashPattern.push_back( 2.0 );
1669  break;
1670  case Qt::DashDotLine:
1671  dashPattern.push_back( 4.0 );
1672  dashPattern.push_back( 2.0 );
1673  dashPattern.push_back( 1.0 );
1674  dashPattern.push_back( 2.0 );
1675  break;
1676  case Qt::DashDotDotLine:
1677  dashPattern.push_back( 4.0 );
1678  dashPattern.push_back( 2.0 );
1679  dashPattern.push_back( 1.0 );
1680  dashPattern.push_back( 2.0 );
1681  dashPattern.push_back( 1.0 );
1682  dashPattern.push_back( 2.0 );
1683  break;
1684 
1685  case Qt::CustomDashLine:
1686  Q_ASSERT( customDashPattern );
1687  pattern = customDashPattern;
1688  break;
1689 
1690  default:
1691  element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
1692  return;
1693  }
1694 
1695  if ( color.isValid() )
1696  {
1697  element.appendChild( createSvgParameterElement( doc, "stroke", color.name() ) );
1698  if ( color.alpha() < 255 )
1699  element.appendChild( createSvgParameterElement( doc, "stroke-opacity", encodeSldAlpha( color.alpha() ) ) );
1700  }
1701  if ( width > 0 )
1702  element.appendChild( createSvgParameterElement( doc, "stroke-width", QString::number( width ) ) );
1703  if ( penJoinStyle )
1704  element.appendChild( createSvgParameterElement( doc, "stroke-linejoin", encodeSldLineJoinStyle( *penJoinStyle ) ) );
1705  if ( penCapStyle )
1706  element.appendChild( createSvgParameterElement( doc, "stroke-linecap", encodeSldLineCapStyle( *penCapStyle ) ) );
1707 
1708  if ( pattern->size() > 0 )
1709  {
1710  element.appendChild( createSvgParameterElement( doc, "stroke-dasharray", encodeSldRealVector( *pattern ) ) );
1711  if ( !qgsDoubleNear( dashOffset, 0.0 ) )
1712  element.appendChild( createSvgParameterElement( doc, "stroke-dashoffset", QString::number( dashOffset ) ) );
1713  }
1714 }
1715 
1716 
1717 bool QgsSymbolLayerV2Utils::lineFromSld( QDomElement &element,
1718  Qt::PenStyle &penStyle, QColor &color, double &width,
1719  Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
1720  QVector<qreal> *customDashPattern, double *dashOffset )
1721 {
1722  QgsDebugMsg( "Entered." );
1723 
1724  penStyle = Qt::SolidLine;
1725  color = QColor( "#000000" );
1726  width = 1;
1727  if ( penJoinStyle )
1728  *penJoinStyle = Qt::BevelJoin;
1729  if ( penCapStyle )
1730  *penCapStyle = Qt::SquareCap;
1731  if ( customDashPattern )
1732  customDashPattern->clear();
1733  if ( dashOffset )
1734  *dashOffset = 0;
1735 
1736  if ( element.isNull() )
1737  {
1738  penStyle = Qt::NoPen;
1739  color = QColor();
1740  return true;
1741  }
1742 
1743  QgsStringMap svgParams = getSvgParameterList( element );
1744  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
1745  {
1746  QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
1747 
1748  if ( it.key() == "stroke" )
1749  {
1750  color = QColor( it.value() );
1751  }
1752  else if ( it.key() == "stroke-opacity" )
1753  {
1754  color.setAlpha( decodeSldAlpha( it.value() ) );
1755  }
1756  else if ( it.key() == "stroke-width" )
1757  {
1758  bool ok;
1759  double w = it.value().toDouble( &ok );
1760  if ( ok )
1761  width = w;
1762  }
1763  else if ( it.key() == "stroke-linejoin" && penJoinStyle )
1764  {
1765  *penJoinStyle = decodeSldLineJoinStyle( it.value() );
1766  }
1767  else if ( it.key() == "stroke-linecap" && penCapStyle )
1768  {
1769  *penCapStyle = decodeSldLineCapStyle( it.value() );
1770  }
1771  else if ( it.key() == "stroke-dasharray" )
1772  {
1773  QVector<qreal> dashPattern = decodeSldRealVector( it.value() );
1774  if ( dashPattern.size() > 0 )
1775  {
1776  // convert the dasharray to one of the QT pen style,
1777  // if no match is found then set pen style to CustomDashLine
1778  bool dashPatternFound = false;
1779 
1780  if ( dashPattern.count() == 2 )
1781  {
1782  if ( dashPattern.at( 0 ) == 4.0 &&
1783  dashPattern.at( 1 ) == 2.0 )
1784  {
1785  penStyle = Qt::DashLine;
1786  dashPatternFound = true;
1787  }
1788  else if ( dashPattern.at( 0 ) == 1.0 &&
1789  dashPattern.at( 1 ) == 2.0 )
1790  {
1791  penStyle = Qt::DotLine;
1792  dashPatternFound = true;
1793  }
1794  }
1795  else if ( dashPattern.count() == 4 )
1796  {
1797  if ( dashPattern.at( 0 ) == 4.0 &&
1798  dashPattern.at( 1 ) == 2.0 &&
1799  dashPattern.at( 2 ) == 1.0 &&
1800  dashPattern.at( 3 ) == 2.0 )
1801  {
1802  penStyle = Qt::DashDotLine;
1803  dashPatternFound = true;
1804  }
1805  }
1806  else if ( dashPattern.count() == 6 )
1807  {
1808  if ( dashPattern.at( 0 ) == 4.0 &&
1809  dashPattern.at( 1 ) == 2.0 &&
1810  dashPattern.at( 2 ) == 1.0 &&
1811  dashPattern.at( 3 ) == 2.0 &&
1812  dashPattern.at( 4 ) == 1.0 &&
1813  dashPattern.at( 5 ) == 2.0 )
1814  {
1815  penStyle = Qt::DashDotDotLine;
1816  dashPatternFound = true;
1817  }
1818  }
1819 
1820  // default case: set pen style to CustomDashLine
1821  if ( !dashPatternFound )
1822  {
1823  if ( customDashPattern )
1824  {
1825  penStyle = Qt::CustomDashLine;
1826  *customDashPattern = dashPattern;
1827  }
1828  else
1829  {
1830  QgsDebugMsg( "custom dash pattern required but not provided. Using default dash pattern." );
1831  penStyle = Qt::DashLine;
1832  }
1833  }
1834  }
1835  }
1836  else if ( it.key() == "stroke-dashoffset" && dashOffset )
1837  {
1838  bool ok;
1839  double d = it.value().toDouble( &ok );
1840  if ( ok )
1841  *dashOffset = d;
1842  }
1843  }
1844 
1845  return true;
1846 }
1847 
1848 void QgsSymbolLayerV2Utils::externalGraphicToSld( QDomDocument &doc, QDomElement &element,
1849  QString path, QString mime,
1850  QColor color, double size )
1851 {
1852  QDomElement externalGraphicElem = doc.createElement( "se:ExternalGraphic" );
1853  element.appendChild( externalGraphicElem );
1854 
1855  createOnlineResourceElement( doc, externalGraphicElem, path, mime );
1856 
1857  //TODO: missing a way to handle svg color. Should use <se:ColorReplacement>
1858  Q_UNUSED( color );
1859 
1860  if ( size >= 0 )
1861  {
1862  QDomElement sizeElem = doc.createElement( "se:Size" );
1863  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
1864  element.appendChild( sizeElem );
1865  }
1866 }
1867 
1869  QString &path, QString &mime,
1870  QColor &color, double &size )
1871 {
1872  QgsDebugMsg( "Entered." );
1873  Q_UNUSED( color );
1874 
1875  QDomElement externalGraphicElem = element.firstChildElement( "ExternalGraphic" );
1876  if ( externalGraphicElem.isNull() )
1877  return false;
1878 
1879  onlineResourceFromSldElement( externalGraphicElem, path, mime );
1880 
1881  QDomElement sizeElem = element.firstChildElement( "Size" );
1882  if ( !sizeElem.isNull() )
1883  {
1884  bool ok;
1885  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
1886  if ( ok )
1887  size = s;
1888  }
1889 
1890  return true;
1891 }
1892 
1893 void QgsSymbolLayerV2Utils::externalMarkerToSld( QDomDocument &doc, QDomElement &element,
1894  QString path, QString format, int *markIndex,
1895  QColor color, double size )
1896 {
1897  QDomElement markElem = doc.createElement( "se:Mark" );
1898  element.appendChild( markElem );
1899 
1900  createOnlineResourceElement( doc, markElem, path, format );
1901 
1902  if ( markIndex )
1903  {
1904  QDomElement markIndexElem = doc.createElement( "se:MarkIndex" );
1905  markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
1906  markElem.appendChild( markIndexElem );
1907  }
1908 
1909  // <Fill>
1910  QDomElement fillElem = doc.createElement( "se:Fill" );
1911  fillToSld( doc, fillElem, Qt::SolidPattern, color );
1912  markElem.appendChild( fillElem );
1913 
1914  // <Size>
1915  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
1916  {
1917  QDomElement sizeElem = doc.createElement( "se:Size" );
1918  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
1919  element.appendChild( sizeElem );
1920  }
1921 }
1922 
1924  QString &path, QString &format, int &markIndex,
1925  QColor &color, double &size )
1926 {
1927  QgsDebugMsg( "Entered." );
1928 
1929  color = QColor();
1930  markIndex = -1;
1931  size = -1;
1932 
1933  QDomElement markElem = element.firstChildElement( "Mark" );
1934  if ( markElem.isNull() )
1935  return false;
1936 
1937  onlineResourceFromSldElement( markElem, path, format );
1938 
1939  QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
1940  if ( !markIndexElem.isNull() )
1941  {
1942  bool ok;
1943  int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
1944  if ( ok )
1945  markIndex = i;
1946  }
1947 
1948  // <Fill>
1949  QDomElement fillElem = markElem.firstChildElement( "Fill" );
1950  Qt::BrushStyle b = Qt::SolidPattern;
1951  fillFromSld( fillElem, b, color );
1952  // ignore brush style, solid expected
1953 
1954  // <Size>
1955  QDomElement sizeElem = element.firstChildElement( "Size" );
1956  if ( !sizeElem.isNull() )
1957  {
1958  bool ok;
1959  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
1960  if ( ok )
1961  size = s;
1962  }
1963 
1964  return true;
1965 }
1966 
1967 void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
1968  QString name, QColor color, QColor borderColor,
1969  double borderWidth, double size )
1970 {
1971  wellKnownMarkerToSld( doc, element, name, color, borderColor, Qt::SolidLine, borderWidth, size );
1972 }
1973 
1974 void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
1975  QString name, QColor color, QColor borderColor, Qt::PenStyle borderStyle,
1976  double borderWidth, double size )
1977 {
1978  QDomElement markElem = doc.createElement( "se:Mark" );
1979  element.appendChild( markElem );
1980 
1981  QDomElement wellKnownNameElem = doc.createElement( "se:WellKnownName" );
1982  wellKnownNameElem.appendChild( doc.createTextNode( name ) );
1983  markElem.appendChild( wellKnownNameElem );
1984 
1985  // <Fill>
1986  if ( color.isValid() )
1987  {
1988  QDomElement fillElem = doc.createElement( "se:Fill" );
1989  fillToSld( doc, fillElem, Qt::SolidPattern, color );
1990  markElem.appendChild( fillElem );
1991  }
1992 
1993  // <Stroke>
1994  if ( borderColor.isValid() )
1995  {
1996  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1997  lineToSld( doc, strokeElem, borderStyle, borderColor, borderWidth );
1998  markElem.appendChild( strokeElem );
1999  }
2000 
2001  // <Size>
2002  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
2003  {
2004  QDomElement sizeElem = doc.createElement( "se:Size" );
2005  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
2006  element.appendChild( sizeElem );
2007  }
2008 }
2009 
2011  QString &name, QColor &color, QColor &borderColor,
2012  double &borderWidth, double &size )
2013 {
2014  Qt::PenStyle borderStyle;
2015  return wellKnownMarkerFromSld( element, name, color, borderColor, borderStyle, borderWidth, size );
2016 }
2017 
2019  QString &name, QColor &color, QColor &borderColor, Qt::PenStyle &borderStyle,
2020  double &borderWidth, double &size )
2021 {
2022  QgsDebugMsg( "Entered." );
2023 
2024  name = "square";
2025  color = QColor();
2026  borderColor = QColor( "#000000" );
2027  borderWidth = 1;
2028  size = 6;
2029 
2030  QDomElement markElem = element.firstChildElement( "Mark" );
2031  if ( markElem.isNull() )
2032  return false;
2033 
2034  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
2035  if ( !wellKnownNameElem.isNull() )
2036  {
2037  name = wellKnownNameElem.firstChild().nodeValue();
2038  QgsDebugMsg( "found Mark with well known name: " + name );
2039  }
2040 
2041  // <Fill>
2042  QDomElement fillElem = markElem.firstChildElement( "Fill" );
2043  Qt::BrushStyle b = Qt::SolidPattern;
2044  fillFromSld( fillElem, b, color );
2045  // ignore brush style, solid expected
2046 
2047  // <Stroke>
2048  QDomElement strokeElem = markElem.firstChildElement( "Stroke" );
2049  lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
2050  // ignore border style, solid expected
2051 
2052  // <Size>
2053  QDomElement sizeElem = element.firstChildElement( "Size" );
2054  if ( !sizeElem.isNull() )
2055  {
2056  bool ok;
2057  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2058  if ( ok )
2059  size = s;
2060  }
2061 
2062  return true;
2063 }
2064 
2065 void QgsSymbolLayerV2Utils::createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc )
2066 {
2067  if ( !rotationFunc.isEmpty() )
2068  {
2069  QDomElement rotationElem = doc.createElement( "se:Rotation" );
2070  createFunctionElement( doc, rotationElem, rotationFunc );
2071  element.appendChild( rotationElem );
2072  }
2073 }
2074 
2075 bool QgsSymbolLayerV2Utils::rotationFromSldElement( QDomElement &element, QString &rotationFunc )
2076 {
2077  QDomElement rotationElem = element.firstChildElement( "Rotation" );
2078  if ( !rotationElem.isNull() )
2079  {
2080  return functionFromSldElement( rotationElem, rotationFunc );
2081  }
2082  return true;
2083 }
2084 
2085 
2086 void QgsSymbolLayerV2Utils::createOpacityElement( QDomDocument &doc, QDomElement &element, QString alphaFunc )
2087 {
2088  if ( !alphaFunc.isEmpty() )
2089  {
2090  QDomElement opacityElem = doc.createElement( "se:Opacity" );
2091  createFunctionElement( doc, opacityElem, alphaFunc );
2092  element.appendChild( opacityElem );
2093  }
2094 }
2095 
2096 bool QgsSymbolLayerV2Utils::opacityFromSldElement( QDomElement &element, QString &alphaFunc )
2097 {
2098  QDomElement opacityElem = element.firstChildElement( "Opacity" );
2099  if ( !opacityElem.isNull() )
2100  {
2101  return functionFromSldElement( opacityElem, alphaFunc );
2102  }
2103  return true;
2104 }
2105 
2106 void QgsSymbolLayerV2Utils::createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset )
2107 {
2108  if ( offset.isNull() )
2109  return;
2110 
2111  QDomElement displacementElem = doc.createElement( "se:Displacement" );
2112  element.appendChild( displacementElem );
2113 
2114  QDomElement dispXElem = doc.createElement( "se:DisplacementX" );
2115  dispXElem.appendChild( doc.createTextNode( QString::number( offset.x() ) ) );
2116 
2117  QDomElement dispYElem = doc.createElement( "se:DisplacementY" );
2118  dispYElem.appendChild( doc.createTextNode( QString::number( offset.y() ) ) );
2119 
2120  displacementElem.appendChild( dispXElem );
2121  displacementElem.appendChild( dispYElem );
2122 }
2123 
2124 bool QgsSymbolLayerV2Utils::displacementFromSldElement( QDomElement &element, QPointF &offset )
2125 {
2126  offset = QPointF( 0, 0 );
2127 
2128  QDomElement displacementElem = element.firstChildElement( "Displacement" );
2129  if ( displacementElem.isNull() )
2130  return true;
2131 
2132  QDomElement dispXElem = displacementElem.firstChildElement( "DisplacementX" );
2133  if ( !dispXElem.isNull() )
2134  {
2135  bool ok;
2136  double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
2137  if ( ok )
2138  offset.setX( offsetX );
2139  }
2140 
2141  QDomElement dispYElem = displacementElem.firstChildElement( "DisplacementY" );
2142  if ( !dispYElem.isNull() )
2143  {
2144  bool ok;
2145  double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
2146  if ( ok )
2147  offset.setY( offsetY );
2148  }
2149 
2150  return true;
2151 }
2152 
2153 void QgsSymbolLayerV2Utils::labelTextToSld( QDomDocument &doc, QDomElement &element,
2154  QString label, QFont font,
2155  QColor color, double size )
2156 {
2157  QDomElement labelElem = doc.createElement( "se:Label" );
2158  labelElem.appendChild( doc.createTextNode( label ) );
2159  element.appendChild( labelElem );
2160 
2161  QDomElement fontElem = doc.createElement( "se:Font" );
2162  element.appendChild( fontElem );
2163 
2164  fontElem.appendChild( createSvgParameterElement( doc, "font-family", font.family() ) );
2165 #if 0
2166  fontElem.appendChild( createSldParameterElement( doc, "font-style", encodeSldFontStyle( font.style() ) ) );
2167  fontElem.appendChild( createSldParameterElement( doc, "font-weight", encodeSldFontWeight( font.weight() ) ) );
2168 #endif
2169  fontElem.appendChild( createSvgParameterElement( doc, "font-size", QString::number( size ) ) );
2170 
2171  // <Fill>
2172  if ( color.isValid() )
2173  {
2174  QDomElement fillElem = doc.createElement( "Fill" );
2175  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2176  element.appendChild( fillElem );
2177  }
2178 }
2179 
2180 QString QgsSymbolLayerV2Utils::ogrFeatureStylePen( double width, double mmScaleFactor, double mapUnitScaleFactor, const QColor& c,
2181  Qt::PenJoinStyle joinStyle,
2182  Qt::PenCapStyle capStyle,
2183  double offset,
2184  const QVector<qreal>* dashPattern )
2185 {
2186  QString penStyle;
2187  penStyle.append( "PEN(" );
2188  penStyle.append( "c:" );
2189  penStyle.append( c.name() );
2190  penStyle.append( ",w:" );
2191  //dxf driver writes ground units as mm? Should probably be changed in ogr
2192  penStyle.append( QString::number( width * mmScaleFactor ) );
2193  penStyle.append( "mm" );
2194 
2195  //dash dot vector
2196  if ( dashPattern && dashPattern->size() > 0 )
2197  {
2198  penStyle.append( ",p:\"" );
2199  QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
2200  for ( ; pIt != dashPattern->constEnd(); ++pIt )
2201  {
2202  if ( pIt != dashPattern->constBegin() )
2203  {
2204  penStyle.append( " " );
2205  }
2206  penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
2207  penStyle.append( "g" );
2208  }
2209  penStyle.append( "\"" );
2210  }
2211 
2212  //cap
2213  penStyle.append( ",cap:" );
2214  switch ( capStyle )
2215  {
2216  case Qt::SquareCap:
2217  penStyle.append( "p" );
2218  break;
2219  case Qt::RoundCap:
2220  penStyle.append( "r" );
2221  break;
2222  case Qt::FlatCap:
2223  default:
2224  penStyle.append( "b" );
2225  }
2226 
2227  //join
2228  penStyle.append( ",j:" );
2229  switch ( joinStyle )
2230  {
2231  case Qt::BevelJoin:
2232  penStyle.append( "b" );
2233  break;
2234  case Qt::RoundJoin:
2235  penStyle.append( "r" );
2236  break;
2237  case Qt::MiterJoin:
2238  default:
2239  penStyle.append( "m" );
2240  }
2241 
2242  //offset
2243  if ( !qgsDoubleNear( offset, 0.0 ) )
2244  {
2245  penStyle.append( ",dp:" );
2246  penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
2247  penStyle.append( "g" );
2248  }
2249 
2250  penStyle.append( ")" );
2251  return penStyle;
2252 }
2253 
2254 QString QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( const QColor& fillColor )
2255 {
2256  QString brushStyle;
2257  brushStyle.append( "BRUSH(" );
2258  brushStyle.append( "fc:" );
2259  brushStyle.append( fillColor.name() );
2260  brushStyle.append( ")" );
2261  return brushStyle;
2262 }
2263 
2264 void QgsSymbolLayerV2Utils::createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc )
2265 {
2266  if ( geomFunc.isEmpty() )
2267  return;
2268 
2269  QDomElement geometryElem = doc.createElement( "Geometry" );
2270  element.appendChild( geometryElem );
2271 
2272  /* About using a function withing the Geometry tag.
2273  *
2274  * The SLD specification <= 1.1 is vague:
2275  * "In principle, a fixed geometry could be defined using GML or
2276  * operators could be defined for computing the geometry from
2277  * references or literals. However, using a feature property directly
2278  * is by far the most commonly useful method."
2279  *
2280  * Even if it seems that specs should take care all the possible cases,
2281  * looking at the XML schema fragment that encodes the Geometry element,
2282  * it has to be a PropertyName element:
2283  * <xsd:element name="Geometry">
2284  * <xsd:complexType>
2285  * <xsd:sequence>
2286  * <xsd:element ref="ogc:PropertyName"/>
2287  * </xsd:sequence>
2288  * </xsd:complexType>
2289  * </xsd:element>
2290  *
2291  * Anyway we will use a ogc:Function to handle geometry transformations
2292  * like offset, centroid, ...
2293  */
2294 
2295  createFunctionElement( doc, geometryElem, geomFunc );
2296 }
2297 
2298 bool QgsSymbolLayerV2Utils::geometryFromSldElement( QDomElement &element, QString &geomFunc )
2299 {
2300  QDomElement geometryElem = element.firstChildElement( "Geometry" );
2301  if ( geometryElem.isNull() )
2302  return true;
2303 
2304  return functionFromSldElement( geometryElem, geomFunc );
2305 }
2306 
2307 bool QgsSymbolLayerV2Utils::createFunctionElement( QDomDocument &doc, QDomElement &element, QString function )
2308 {
2309  // let's use QgsExpression to generate the SLD for the function
2310  QgsExpression expr( function );
2311  if ( expr.hasParserError() )
2312  {
2313  element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function ) );
2314  return false;
2315  }
2316  QDomElement filterElem = QgsOgcUtils::expressionToOgcFilter( expr, doc );
2317  if ( !filterElem.isNull() )
2318  element.appendChild( filterElem );
2319  return true;
2320 }
2321 
2322 bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QString &function )
2323 {
2324  QgsDebugMsg( "Entered." );
2325 
2327  if ( !expr )
2328  return false;
2329 
2330  bool valid = !expr->hasParserError();
2331  if ( !valid )
2332  {
2333  QgsDebugMsg( "parser error: " + expr->parserErrorString() );
2334  }
2335  else
2336  {
2337  function = expr->expression();
2338  }
2339 
2340  delete expr;
2341  return valid;
2342 }
2343 
2344 void QgsSymbolLayerV2Utils::createOnlineResourceElement( QDomDocument &doc, QDomElement &element,
2345  QString path, QString format )
2346 {
2347  // get resource url or relative path
2348  QString url = symbolPathToName( path );
2349  QDomElement onlineResourceElem = doc.createElement( "se:OnlineResource" );
2350  onlineResourceElem.setAttribute( "xlink:type", "simple" );
2351  onlineResourceElem.setAttribute( "xlink:href", url );
2352  element.appendChild( onlineResourceElem );
2353 
2354  QDomElement formatElem = doc.createElement( "se:Format" );
2355  formatElem.appendChild( doc.createTextNode( format ) );
2356  element.appendChild( formatElem );
2357 }
2358 
2359 bool QgsSymbolLayerV2Utils::onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format )
2360 {
2361  QgsDebugMsg( "Entered." );
2362 
2363  QDomElement onlineResourceElem = element.firstChildElement( "OnlineResource" );
2364  if ( onlineResourceElem.isNull() )
2365  return false;
2366 
2367  path = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
2368 
2369  QDomElement formatElem = element.firstChildElement( "Format" );
2370  if ( formatElem.isNull() )
2371  return false; // OnlineResource requires a Format sibling element
2372 
2373  format = formatElem.firstChild().nodeValue();
2374  return true;
2375 }
2376 
2377 
2378 QDomElement QgsSymbolLayerV2Utils::createSvgParameterElement( QDomDocument &doc, QString name, QString value )
2379 {
2380  QDomElement nodeElem = doc.createElement( "se:SvgParameter" );
2381  nodeElem.setAttribute( "name", name );
2382  nodeElem.appendChild( doc.createTextNode( value ) );
2383  return nodeElem;
2384 }
2385 
2387 {
2388  QgsStringMap params;
2389 
2390  QDomElement paramElem = element.firstChildElement();
2391  while ( !paramElem.isNull() )
2392  {
2393  if ( paramElem.localName() == "SvgParameter" || paramElem.localName() == "CssParameter" )
2394  {
2395  QString name = paramElem.attribute( "name" );
2396  QString value = paramElem.firstChild().nodeValue();
2397 
2398  if ( !name.isEmpty() && !value.isEmpty() )
2399  params[ name ] = value;
2400  }
2401 
2402  paramElem = paramElem.nextSiblingElement();
2403  }
2404 
2405  return params;
2406 }
2407 
2408 QDomElement QgsSymbolLayerV2Utils::createVendorOptionElement( QDomDocument &doc, QString name, QString value )
2409 {
2410  QDomElement nodeElem = doc.createElement( "VendorOption" );
2411  nodeElem.setAttribute( "name", name );
2412  nodeElem.appendChild( doc.createTextNode( value ) );
2413  return nodeElem;
2414 }
2415 
2417 {
2418  QgsStringMap params;
2419 
2420  QDomElement paramElem = element.firstChildElement( "VendorOption" );
2421  while ( !paramElem.isNull() )
2422  {
2423  QString name = paramElem.attribute( "name" );
2424  QString value = paramElem.firstChild().nodeValue();
2425 
2426  if ( !name.isEmpty() && !value.isEmpty() )
2427  params[ name ] = value;
2428 
2429  paramElem = paramElem.nextSiblingElement( "VendorOption" );
2430  }
2431 
2432  return params;
2433 }
2434 
2435 
2437 {
2438  QgsStringMap props;
2439  QDomElement e = element.firstChildElement();
2440  while ( !e.isNull() )
2441  {
2442  if ( e.tagName() != "prop" )
2443  {
2444  QgsDebugMsg( "unknown tag " + e.tagName() );
2445  }
2446  else
2447  {
2448  QString propKey = e.attribute( "k" );
2449  QString propValue = e.attribute( "v" );
2450  props[propKey] = propValue;
2451  }
2452  e = e.nextSiblingElement();
2453  }
2454  return props;
2455 }
2456 
2457 
2458 void QgsSymbolLayerV2Utils::saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element )
2459 {
2460  for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
2461  {
2462  QDomElement propEl = doc.createElement( "prop" );
2463  propEl.setAttribute( "k", it.key() );
2464  propEl.setAttribute( "v", it.value() );
2465  element.appendChild( propEl );
2466  }
2467 }
2468 
2470 {
2471  // go through symbols one-by-one and load them
2472 
2473  QgsSymbolV2Map symbols;
2474  QDomElement e = element.firstChildElement();
2475 
2476  while ( !e.isNull() )
2477  {
2478  if ( e.tagName() == "symbol" )
2479  {
2481  if ( symbol != NULL )
2482  symbols.insert( e.attribute( "name" ), symbol );
2483  }
2484  else
2485  {
2486  QgsDebugMsg( "unknown tag: " + e.tagName() );
2487  }
2488  e = e.nextSiblingElement();
2489  }
2490 
2491 
2492  // now walk through the list of symbols and find those prefixed with @
2493  // these symbols are sub-symbols of some other symbol layers
2494  // e.g. symbol named "@foo@1" is sub-symbol of layer 1 in symbol "foo"
2495  QStringList subsymbols;
2496 
2497  for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
2498  {
2499  if ( it.key()[0] != '@' )
2500  continue;
2501 
2502  // add to array (for deletion)
2503  subsymbols.append( it.key() );
2504 
2505  QStringList parts = it.key().split( "@" );
2506  if ( parts.count() < 3 )
2507  {
2508  QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
2509  delete it.value(); // we must delete it
2510  continue; // some invalid syntax
2511  }
2512  QString symname = parts[1];
2513  int symlayer = parts[2].toInt();
2514 
2515  if ( !symbols.contains( symname ) )
2516  {
2517  QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
2518  delete it.value(); // we must delete it
2519  continue;
2520  }
2521 
2522  QgsSymbolV2* sym = symbols[symname];
2523  if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
2524  {
2525  QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
2526  delete it.value(); // we must delete it
2527  continue;
2528  }
2529 
2530  // set subsymbol takes ownership
2531  bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
2532  if ( !res )
2533  {
2534  QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
2535  }
2536 
2537 
2538  }
2539 
2540  // now safely remove sub-symbol entries (they have been already deleted or the ownership was taken away)
2541  for ( int i = 0; i < subsymbols.count(); i++ )
2542  symbols.take( subsymbols[i] );
2543 
2544  return symbols;
2545 }
2546 
2547 QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString tagName, QDomDocument& doc )
2548 {
2549  QDomElement symbolsElem = doc.createElement( tagName );
2550 
2551  // save symbols
2552  for ( QMap<QString, QgsSymbolV2*>::iterator its = symbols.begin(); its != symbols.end(); ++its )
2553  {
2554  QDomElement symEl = saveSymbol( its.key(), its.value(), doc );
2555  symbolsElem.appendChild( symEl );
2556  }
2557 
2558  return symbolsElem;
2559 }
2560 
2562 {
2563  foreach ( QString name, symbols.keys() )
2564  {
2565  delete symbols.value( name );
2566  }
2567  symbols.clear();
2568 }
2569 
2570 
2572 {
2573  QString rampType = element.attribute( "type" );
2574 
2575  // parse properties
2577 
2578  if ( rampType == "gradient" )
2579  return QgsVectorGradientColorRampV2::create( props );
2580  else if ( rampType == "random" )
2581  return QgsVectorRandomColorRampV2::create( props );
2582  else if ( rampType == "colorbrewer" )
2584  else if ( rampType == "cpt-city" )
2585  return QgsCptCityColorRampV2::create( props );
2586  else
2587  {
2588  QgsDebugMsg( "unknown colorramp type " + rampType );
2589  return NULL;
2590  }
2591 }
2592 
2593 
2594 QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc )
2595 {
2596  QDomElement rampEl = doc.createElement( "colorramp" );
2597  rampEl.setAttribute( "type", ramp->type() );
2598  rampEl.setAttribute( "name", name );
2599 
2600  QgsSymbolLayerV2Utils::saveProperties( ramp->properties(), doc, rampEl );
2601  return rampEl;
2602 }
2603 
2604 // parse color definition with format "rgb(0,0,0)" or "0,0,0"
2605 // should support other formats like FFFFFF
2606 QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr )
2607 {
2608  if ( colorStr.startsWith( "rgb(" ) )
2609  {
2610  colorStr = colorStr.mid( 4, colorStr.size() - 5 ).trimmed();
2611  }
2612  QStringList p = colorStr.split( QChar( ',' ) );
2613  if ( p.count() != 3 )
2614  return QColor();
2615  return QColor( p[0].toInt(), p[1].toInt(), p[2].toInt() );
2616 }
2617 
2619 {
2620 
2621  if ( u == QgsSymbolV2::MM )
2622  {
2623  return c.scaleFactor();
2624  }
2625  else //QgsSymbol::MapUnit
2626  {
2627  double mup = c.mapToPixel().mapUnitsPerPixel();
2628  if ( mup > 0 )
2629  {
2630  return 1.0 / mup;
2631  }
2632  else
2633  {
2634  return 1.0;
2635  }
2636  }
2637 }
2638 
2640 {
2641  if ( u == QgsSymbolV2::MM )
2642  {
2643  return ( c.scaleFactor() * c.rasterScaleFactor() );
2644  }
2645  else //QgsSymbol::MapUnit
2646  {
2647  double mup = c.mapToPixel().mapUnitsPerPixel();
2648  if ( mup > 0 )
2649  {
2650  return c.rasterScaleFactor() / c.mapToPixel().mapUnitsPerPixel();
2651  }
2652  else
2653  {
2654  return 1.0;
2655  }
2656  }
2657 }
2658 
2660 {
2661  QgsRenderContext context;
2662  context.setPainter( p );
2663  context.setRasterScaleFactor( 1.0 );
2664  if ( p && p->device() )
2665  {
2666  context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
2667  }
2668  else
2669  {
2670  context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
2671  }
2672  return context;
2673 }
2674 
2675 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
2676 {
2677  if ( !image )
2678  {
2679  return;
2680  }
2681 
2682  QRgb myRgb;
2683  QImage::Format format = image->format();
2684  if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
2685  {
2686  QgsDebugMsg( "no alpha channel." );
2687  return;
2688  }
2689 
2690  //change the alpha component of every pixel
2691  for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
2692  {
2693  QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
2694  for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
2695  {
2696  myRgb = scanLine[widthIndex];
2697  if ( format == QImage::Format_ARGB32_Premultiplied )
2698  scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
2699  else
2700  scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
2701  }
2702  }
2703 }
2704 
2705 void QgsSymbolLayerV2Utils::blurImageInPlace( QImage& image, const QRect& rect, int radius, bool alphaOnly )
2706 {
2707  // culled from Qt's qpixmapfilter.cpp, see: http://www.qtcentre.org/archive/index.php/t-26534.html
2708  int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
2709  int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius-1];
2710 
2711  if ( image.format() != QImage::Format_ARGB32_Premultiplied
2712  && image.format() != QImage::Format_RGB32 )
2713  {
2714  image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
2715  }
2716 
2717  int r1 = rect.top();
2718  int r2 = rect.bottom();
2719  int c1 = rect.left();
2720  int c2 = rect.right();
2721 
2722  int bpl = image.bytesPerLine();
2723  int rgba[4];
2724  unsigned char* p;
2725 
2726  int i1 = 0;
2727  int i2 = 3;
2728 
2729  if ( alphaOnly ) // this seems to only work right for a black color
2730  i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
2731 
2732  for ( int col = c1; col <= c2; col++ )
2733  {
2734  p = image.scanLine( r1 ) + col * 4;
2735  for ( int i = i1; i <= i2; i++ )
2736  rgba[i] = p[i] << 4;
2737 
2738  p += bpl;
2739  for ( int j = r1; j < r2; j++, p += bpl )
2740  for ( int i = i1; i <= i2; i++ )
2741  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2742  }
2743 
2744  for ( int row = r1; row <= r2; row++ )
2745  {
2746  p = image.scanLine( row ) + c1 * 4;
2747  for ( int i = i1; i <= i2; i++ )
2748  rgba[i] = p[i] << 4;
2749 
2750  p += 4;
2751  for ( int j = c1; j < c2; j++, p += 4 )
2752  for ( int i = i1; i <= i2; i++ )
2753  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2754  }
2755 
2756  for ( int col = c1; col <= c2; col++ )
2757  {
2758  p = image.scanLine( r2 ) + col * 4;
2759  for ( int i = i1; i <= i2; i++ )
2760  rgba[i] = p[i] << 4;
2761 
2762  p -= bpl;
2763  for ( int j = r1; j < r2; j++, p -= bpl )
2764  for ( int i = i1; i <= i2; i++ )
2765  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2766  }
2767 
2768  for ( int row = r1; row <= r2; row++ )
2769  {
2770  p = image.scanLine( row ) + c2 * 4;
2771  for ( int i = i1; i <= i2; i++ )
2772  rgba[i] = p[i] << 4;
2773 
2774  p -= 4;
2775  for ( int j = c1; j < c2; j++, p -= 4 )
2776  for ( int i = i1; i <= i2; i++ )
2777  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2778  }
2779 }
2780 
2781 void QgsSymbolLayerV2Utils::premultiplyColor( QColor &rgb, int alpha )
2782 {
2783  int r = 0, g = 0, b = 0;
2784  double alphaFactor = 1.0;
2785 
2786  if ( alpha != 255 && alpha > 0 )
2787  {
2788  // Semi-transparent pixel. We need to adjust the colors for ARGB32_Premultiplied images
2789  // where color values have to be premultiplied by alpha
2790 
2791  rgb.getRgb( &r, &g, &b );
2792 
2793  alphaFactor = alpha / 255.;
2794  r *= alphaFactor;
2795  g *= alphaFactor;
2796  b *= alphaFactor;
2797  rgb.setRgb( r, g, b, alpha );
2798  }
2799  else if ( alpha == 0 )
2800  {
2801  rgb.setRgb( 0, 0, 0, 0 );
2802  }
2803 }
2804 
2805 #if 0
2806 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
2807 {
2808  switch ( lhs.type() )
2809  {
2810  case QVariant::Int:
2811  return lhs.toInt() < rhs.toInt();
2812  case QVariant::UInt:
2813  return lhs.toUInt() < rhs.toUInt();
2814  case QVariant::LongLong:
2815  return lhs.toLongLong() < rhs.toLongLong();
2816  case QVariant::ULongLong:
2817  return lhs.toULongLong() < rhs.toULongLong();
2818  case QVariant::Double:
2819  return lhs.toDouble() < rhs.toDouble();
2820  case QVariant::Char:
2821  return lhs.toChar() < rhs.toChar();
2822  case QVariant::Date:
2823  return lhs.toDate() < rhs.toDate();
2824  case QVariant::Time:
2825  return lhs.toTime() < rhs.toTime();
2826  case QVariant::DateTime:
2827  return lhs.toDateTime() < rhs.toDateTime();
2828  default:
2829  return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
2830  }
2831 }
2832 
2833 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
2834 {
2835  return ! _QVariantLessThan( lhs, rhs );
2836 }
2837 #endif
2838 
2839 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
2840 {
2841  if ( order == Qt::AscendingOrder )
2842  {
2843  //qSort( list.begin(), list.end(), _QVariantLessThan );
2844  qSort( list.begin(), list.end(), qgsVariantLessThan );
2845  }
2846  else // Qt::DescendingOrder
2847  {
2848  //qSort( list.begin(), list.end(), _QVariantGreaterThan );
2849  qSort( list.begin(), list.end(), qgsVariantGreaterThan );
2850  }
2851 }
2852 
2853 QPointF QgsSymbolLayerV2Utils::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance )
2854 {
2855  double dx = directionPoint.x() - startPoint.x();
2856  double dy = directionPoint.y() - startPoint.y();
2857  double length = sqrt( dx * dx + dy * dy );
2858  double scaleFactor = distance / length;
2859  return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
2860 }
2861 
2862 
2864 {
2865  // copied from QgsMarkerCatalogue - TODO: unify
2866  QStringList list;
2867  QStringList svgPaths = QgsApplication::svgPaths();
2868 
2869  for ( int i = 0; i < svgPaths.size(); i++ )
2870  {
2871  QDir dir( svgPaths[i] );
2872  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
2873  {
2874  svgPaths.insert( i + 1, dir.path() + "/" + item );
2875  }
2876 
2877  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
2878  {
2879  // TODO test if it is correct SVG
2880  list.append( dir.path() + "/" + item );
2881  }
2882  }
2883  return list;
2884 }
2885 
2886 // Stripped down version of listSvgFiles() for specified directory
2887 QStringList QgsSymbolLayerV2Utils::listSvgFilesAt( QString directory )
2888 {
2889  // TODO anything that applies for the listSvgFiles() applies this also
2890 
2891  QStringList list;
2892  QStringList svgPaths;
2893  svgPaths.append( directory );
2894 
2895  for ( int i = 0; i < svgPaths.size(); i++ )
2896  {
2897  QDir dir( svgPaths[i] );
2898  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
2899  {
2900  svgPaths.insert( i + 1, dir.path() + "/" + item );
2901  }
2902 
2903  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
2904  {
2905  list.append( dir.path() + "/" + item );
2906  }
2907  }
2908  return list;
2909 
2910 }
2911 
2913 {
2914  // copied from QgsSymbol::setNamedPointSymbol - TODO: unify
2915 
2916  // we might have a full path...
2917  if ( QFile( name ).exists() )
2918  return QFileInfo( name ).canonicalFilePath();
2919 
2920  // or it might be an url...
2921  if ( name.contains( "://" ) )
2922  {
2923  QUrl url( name );
2924  if ( url.isValid() && !url.scheme().isEmpty() )
2925  {
2926  if ( url.scheme().compare( "file", Qt::CaseInsensitive ) == 0 )
2927  {
2928  // it's a url to a local file
2929  name = url.toLocalFile();
2930  if ( QFile( name ).exists() )
2931  {
2932  return QFileInfo( name ).canonicalFilePath();
2933  }
2934  }
2935  else
2936  {
2937  // it's a url pointing to a online resource
2938  return name;
2939  }
2940  }
2941  }
2942 
2943  // SVG symbol not found - probably a relative path was used
2944 
2945  QStringList svgPaths = QgsApplication::svgPaths();
2946  for ( int i = 0; i < svgPaths.size(); i++ )
2947  {
2948  QString svgPath = svgPaths[i];
2949  if ( svgPath.endsWith( QString( "/" ) ) )
2950  {
2951  svgPath.chop( 1 );
2952  }
2953 
2954  QgsDebugMsg( "SvgPath: " + svgPath );
2955  QFileInfo myInfo( name );
2956  QString myFileName = myInfo.fileName(); // foo.svg
2957  QString myLowestDir = myInfo.dir().dirName();
2958  QString myLocalPath = svgPath + QString( myLowestDir.isEmpty() ? "" : "/" + myLowestDir ) + "/" + myFileName;
2959 
2960  QgsDebugMsg( "Alternative svg path: " + myLocalPath );
2961  if ( QFile( myLocalPath ).exists() )
2962  {
2963  QgsDebugMsg( "Svg found in alternative path" );
2964  return QFileInfo( myLocalPath ).canonicalFilePath();
2965  }
2966  else if ( myInfo.isRelative() )
2967  {
2968  QFileInfo pfi( QgsProject::instance()->fileName() );
2969  QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
2970  if ( pfi.exists() && QFile( alternatePath ).exists() )
2971  {
2972  QgsDebugMsg( "Svg found in alternative path" );
2973  return QFileInfo( alternatePath ).canonicalFilePath();
2974  }
2975  else
2976  {
2977  QgsDebugMsg( "Svg not found in project path" );
2978  }
2979  }
2980  else
2981  {
2982  //couldnt find the file, no happy ending :-(
2983  QgsDebugMsg( "Computed alternate path but no svg there either" );
2984  }
2985  }
2986  return QString();
2987 }
2988 
2990 {
2991  // copied from QgsSymbol::writeXML
2992 
2993  QFileInfo fi( path );
2994  if ( !fi.exists() )
2995  return path;
2996 
2997  path = fi.canonicalFilePath();
2998 
2999  QStringList svgPaths = QgsApplication::svgPaths();
3000 
3001  bool isInSvgPathes = false;
3002  for ( int i = 0; i < svgPaths.size(); i++ )
3003  {
3004  QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
3005 
3006  if ( !dir.isEmpty() && path.startsWith( dir ) )
3007  {
3008  path = path.mid( dir.size() + 1 );
3009  isInSvgPathes = true;
3010  break;
3011  }
3012  }
3013 
3014  if ( isInSvgPathes )
3015  return path;
3016 
3017  return QgsProject::instance()->writePath( path );
3018 }
3019 
3020 QPointF QgsSymbolLayerV2Utils::polygonCentroid( const QPolygonF& points )
3021 {
3022  //Calculate the centroid of points
3023  double cx = 0, cy = 0;
3024  double area, sum = 0;
3025  for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
3026  {
3027  const QPointF& p1 = points[i];
3028  const QPointF& p2 = points[j];
3029  area = p1.x() * p2.y() - p1.y() * p2.x();
3030  sum += area;
3031  cx += ( p1.x() + p2.x() ) * area;
3032  cy += ( p1.y() + p2.y() ) * area;
3033  }
3034  sum *= 3.0;
3035  cx /= sum;
3036  cy /= sum;
3037 
3038  return QPointF( cx, cy );
3039 }
3040 
3041 
3043 {
3044  if ( fieldOrExpression.isEmpty() )
3045  return 0;
3046 
3047  QgsExpression* expr = new QgsExpression( fieldOrExpression );
3048  if ( !expr->hasParserError() )
3049  return expr;
3050 
3051  // now try with quoted field name
3052  delete expr;
3053  QgsExpression* expr2 = new QgsExpression( QgsExpression::quotedColumnRef( fieldOrExpression ) );
3054  Q_ASSERT( !expr2->hasParserError() );
3055  return expr2;
3056 }
3057 
3059 {
3060  const QgsExpression::Node* n = expression->rootNode();
3061 
3062  if ( n && n->nodeType() == QgsExpression::ntColumnRef )
3063  return static_cast<const QgsExpression::NodeColumnRef*>( n )->name();
3064 
3065  return expression->expression();
3066 }
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:38
static QString encodeSldLineJoinStyle(Qt::PenJoinStyle style)
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
static Qt::BrushStyle decodeBrushStyle(QString str)
void setLocked(bool locked)
static QgsSymbolV2Map loadSymbols(QDomElement &element)
static Qt::PenCapStyle decodeSldLineCapStyle(QString str)
virtual NodeType nodeType() const =0
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:96
QgsSymbolLayerV2 * createSymbolLayer(QString name, const QgsStringMap &properties=QgsStringMap()) const
create a new instance of symbol layer given symbol layer name and properties
static QIcon colorRampPreviewIcon(QgsVectorColorRampV2 *ramp, QSize size)
virtual QString type() const =0
static QPixmap colorRampPreviewPixmap(QgsVectorColorRampV2 *ramp, QSize size)
GeometryType
Definition: qgis.h:155
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
static const QStringList svgPaths()
Returns the pathes to svg directories.
const QString expression() const
Return the expression string that was given when created.
SymbolType type() const
Definition: qgssymbolv2.h:78
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void drawPreviewIcon(QPainter *painter, QSize size)
static QString encodeSldUom(QgsSymbolV2::OutputUnit unit, double *scaleFactor)
static void createRotationElement(QDomDocument &doc, QDomElement &element, QString rotationFunc)
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:38
static QgsStringMap getVendorOptionList(QDomElement &element)
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color=QColor())
static QVector< qreal > decodeRealVector(const QString &s)
static bool functionFromSldElement(QDomElement &element, QString &function)
static QString encodeSldFontStyle(QFont::Style style)
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
static QPointF decodePoint(QString str)
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
virtual QgsStringMap properties() const =0
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
static QColor decodeColor(QString str)
static bool convertPolygonSymbolizerToPointMarker(QDomElement &element, QgsSymbolLayerV2List &layerList)
static QDomElement createSvgParameterElement(QDomDocument &doc, QString name, QString value)
static QgsSymbolLayerV2Registry * instance()
return the single instance of this class (instantiate it if not exists)
static QVector< qreal > decodeSldRealVector(const QString &s)
double scaleFactor() const
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:237
static void createOnlineResourceElement(QDomDocument &doc, QDomElement &element, QString path, QString format)
QgsSymbolLayerV2 * createSymbolLayerFromSld(QString name, QDomElement &element) const
create a new instance of symbol layer given symbol layer name and SLD
static bool needMarkerLine(QDomElement &element)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
static bool needPointPatternFill(QDomElement &element)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
double x() const
Definition: qgspoint.h:110
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:210
const GEOSGeometry * asGeos() const
Returns a geos geomtry.
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
static QString encodeColor(QColor color)
static Qt::BrushStyle decodeSldBrushStyle(QString str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
static QString encodePenStyle(Qt::PenStyle style)
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
static QDomElement expressionToOgcFilter(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=0)
Creates OGC filter XML element.
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
static QString symbolPathToName(QString path)
Get symbols's name from its path.
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
static QgsRenderContext createRenderContext(QPainter *p)
Creates a render context for a pixel based device.
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
static QString encodeSldFontWeight(int weight)
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=0)
Create ogr feature style string for pen.
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
void setScaleFactor(double factor)
static QgsSymbolLayerV2 * createFillLayerFromSld(QDomElement &element)
static QString encodePoint(QPointF point)
static QPointF offsetPoint(QPointF pt, double angle, double dist)
static QString encodeSldAlpha(int alpha)
static bool needLinePatternFill(QDomElement &element)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:121
static Qt::PenCapStyle decodePenCapStyle(QString str)
static Qt::PenStyle decodePenStyle(QString str)
static QIcon symbolLayerPreviewIcon(QgsSymbolLayerV2 *layer, QgsSymbolV2::OutputUnit u, QSize size)
void setRenderingPass(int renderingPass)
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
static QStringList listSvgFiles()
Return a list of all available svg files.
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
#define M_PI
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
static QFont::Style decodeSldFontStyle(QString str)
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
static QgsSymbolV2::OutputUnit decodeSldUom(QString str, double *scaleFactor)
int symbolLayerCount()
Definition: qgssymbolv2.h:84
QString writePath(QString filename) const
prepare a filename to save it to the project file
void setPainter(QPainter *p)
static bool needFontMarker(QDomElement &element)
double rasterScaleFactor() const
static void saveProperties(QgsStringMap props, QDomDocument &doc, QDomElement &element)
virtual QgsStringMap properties() const =0
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u)
Returns scale factor painter units -> pixel dimensions.
double mapUnitsPerPixel() const
Return current map units per pixel.
static Qt::PenJoinStyle decodeSldLineJoinStyle(QString str)
static double estimateMaxSymbolBleed(QgsSymbolV2 *symbol)
Returns the maximum estimated bleed for the symbol.
static bool hasExternalGraphic(QDomElement &element)
static QStringList listSvgFilesAt(QString directory)
Return a list of svg files at the specified directory.
A class to represent a point geometry.
Definition: qgspoint.h:63
virtual QColor color(double value) const =0
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 bool needSvgMarker(QDomElement &element)
static bool needSvgFill(QDomElement &element)
static bool geometryFromSldElement(QDomElement &element, QString &geomFunc)
static QgsSymbolLayerV2 * loadSymbolLayer(QDomElement &element)
static QgsSymbolLayerV2 * createLineLayerFromSld(QDomElement &element)
static QString encodeRealVector(const QVector< qreal > &v)
int renderingPass() const
virtual QString layerType() const =0
static QColor parseColor(QString colorStr)
parse color definition with format "rgb(0,0,0)" or "0,0,0"
virtual QgsSymbolV2 * subSymbol()
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QgsPolyline asPolyline() const
return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list ...
static void labelTextToSld(QDomDocument &doc, QDomElement &element, QString label, QFont font, QColor color=QColor(), double size=-1)
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, QColor color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=0, const Qt::PenCapStyle *penCapStyle=0, const QVector< qreal > *customDashPattern=0, double dashOffset=0.0)
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
static int decodeSldFontWeight(QString str)
static void createOpacityElement(QDomDocument &doc, QDomElement &element, QString alphaFunc)
static QString encodeBrushStyle(Qt::BrushStyle style)
static QPointF linesIntersection(QPointF p1, double t1, QPointF p2, double t2)
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
bool isLocked() const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:38
static bool lineInfo(QPointF p1, QPointF p2, double &angle, double &t)
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
static QString _nameForSymbolType(QgsSymbolV2::SymbolType type)
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Return a field name if the whole expression is just a name of the field .
static QString encodeSldRealVector(const QVector< qreal > &v)
static QgsExpression * expressionFromOgcFilter(const QDomElement &element)
Parse XML with OGC filter into QGIS expression.
static QString encodeSldBrushStyle(Qt::BrushStyle style)
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, QString path, QString mime, QColor color, double size=-1)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u)
Returns the line width scale factor depending on the unit and the paint device.
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size)
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
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
double y() const
Definition: qgspoint.h:118
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
static void clearSymbolMap(QgsSymbolV2Map &symbols)
static int decodeSldAlpha(QString str)
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
static QgsStringMap getSvgParameterList(QDomElement &element)
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
static QgsSymbolV2 * loadSymbol(QDomElement &element)
void setRasterScaleFactor(double factor)
static void drawStippledBackround(QPainter *painter, QRect rect)
static bool onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)
QPolygonF offsetLine(QPolygonF polyline, double dist)
calculate line shifted by a specified distance
QgsSymbolLayerV2 * symbolLayer(int layer)
static QgsStringMap parseProperties(QDomElement &element)
virtual void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)=0
static bool hasWellKnownMark(QDomElement &element)
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=0, Qt::PenCapStyle *penCapStyle=0, QVector< qreal > *customDashPattern=0, double *dashOffset=0)
static QPointF pointOnLineWithDistance(const QPointF &startPoint, const QPointF &directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
double size
Definition: qgssvgcache.cpp:77
static bool opacityFromSldElement(QDomElement &element, QString &alphaFunc)
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.h:98
virtual bool setSubSymbol(QgsSymbolV2 *symbol)
void setOutputUnit(QgsSymbolV2::OutputUnit u)
Definition: qgssymbolv2.cpp:86
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:123
static void blurImageInPlace(QImage &image, const QRect &rect, int radius, bool alphaOnly)
Blurs an image in place, e.g.
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
static QString encodeSldLineCapStyle(Qt::PenCapStyle style)
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, QString path, QString format, int *markIndex=0, QColor color=QColor(), double size=-1)
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
static bool needEllipseMarker(QDomElement &element)
static QString encodePenCapStyle(Qt::PenCapStyle style)