QGIS API Documentation  2.5.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  return QString( "%1,%2" ).arg( mapUnitScale.minScale ).arg( mapUnitScale.maxScale );
331 }
332 
334 {
335  QStringList lst = str.split( ',' );
336  if ( lst.count() != 2 )
337  return QgsMapUnitScale();
338  return QgsMapUnitScale( lst[0].toDouble(), lst[1].toDouble() );
339 }
340 
342 {
343  switch ( unit )
344  {
345  case QgsSymbolV2::MM:
346  return "MM";
348  return "MapUnit";
349  default:
350  return "MM";
351  }
352 }
353 
355 {
356  if ( str == "MM" )
357  {
358  return QgsSymbolV2::MM;
359  }
360  else if ( str == "MapUnit" )
361  {
362  return QgsSymbolV2::MapUnit;
363  }
364 
365  // millimeters are default
366  return QgsSymbolV2::MM;
367 }
368 
370 {
371  switch ( unit )
372  {
374  if ( scaleFactor )
375  *scaleFactor = 0.001; // from millimeters to meters
376  return "http://www.opengeospatial.org/se/units/metre";
377 
378  case QgsSymbolV2::MM:
379  default:
380  // pixel is the SLD default uom. The "standardized rendering pixel
381  // size" is defined to be 0.28mm × 0.28mm (millimeters).
382  if ( scaleFactor )
383  *scaleFactor = 0.28; // from millimeters to pixels
384 
385  // http://www.opengeospatial.org/sld/units/pixel
386  return QString();
387  }
388 }
389 
391 {
392  if ( str == "http://www.opengeospatial.org/se/units/metre" )
393  {
394  if ( scaleFactor )
395  *scaleFactor = 1000.0; // from meters to millimeters
396  return QgsSymbolV2::MapUnit;
397  }
398  else if ( str == "http://www.opengeospatial.org/se/units/foot" )
399  {
400  if ( scaleFactor )
401  *scaleFactor = 304.8; // from feet to meters
402  return QgsSymbolV2::MapUnit;
403  }
404 
405  // pixel is the SLD default uom. The "standardized rendering pixel
406  // size" is defined to be 0.28mm x 0.28mm (millimeters).
407  if ( scaleFactor )
408  *scaleFactor = 1 / 0.00028; // from pixels to millimeters
409  return QgsSymbolV2::MM;
410 }
411 
412 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
413 {
414  QString vectorString;
415  QVector<qreal>::const_iterator it = v.constBegin();
416  for ( ; it != v.constEnd(); ++it )
417  {
418  if ( it != v.constBegin() )
419  {
420  vectorString.append( ";" );
421  }
422  vectorString.append( QString::number( *it ) );
423  }
424  return vectorString;
425 }
426 
427 QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
428 {
429  QVector<qreal> resultVector;
430 
431  QStringList realList = s.split( ";" );
432  QStringList::const_iterator it = realList.constBegin();
433  for ( ; it != realList.constEnd(); ++it )
434  {
435  resultVector.append( it->toDouble() );
436  }
437 
438  return resultVector;
439 }
440 
441 QString QgsSymbolLayerV2Utils::encodeSldRealVector( const QVector<qreal>& v )
442 {
443  QString vectorString;
444  QVector<qreal>::const_iterator it = v.constBegin();
445  for ( ; it != v.constEnd(); ++it )
446  {
447  if ( it != v.constBegin() )
448  {
449  vectorString.append( " " );
450  }
451  vectorString.append( QString::number( *it ) );
452  }
453  return vectorString;
454 }
455 
456 QVector<qreal> QgsSymbolLayerV2Utils::decodeSldRealVector( const QString& s )
457 {
458  QVector<qreal> resultVector;
459 
460  QStringList realList = s.split( " " );
461  QStringList::const_iterator it = realList.constBegin();
462  for ( ; it != realList.constEnd(); ++it )
463  {
464  resultVector.append( it->toDouble() );
465  }
466 
467  return resultVector;
468 }
469 
471 {
472  QString encodedValue;
473 
474  switch ( scaleMethod )
475  {
477  encodedValue = "diameter";
478  break;
480  encodedValue = "area";
481  break;
482  }
483  return encodedValue;
484 }
485 
487 {
488  QgsSymbolV2::ScaleMethod scaleMethod;
489 
490  if ( str == "diameter" )
491  {
492  scaleMethod = QgsSymbolV2::ScaleDiameter;
493  }
494  else
495  {
496  scaleMethod = QgsSymbolV2::ScaleArea;
497  }
498 
499  return scaleMethod;
500 }
501 
502 QPainter::CompositionMode QgsSymbolLayerV2Utils::decodeBlendMode( const QString &s )
503 {
504  if ( s.compare( "Lighten", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Lighten;
505  if ( s.compare( "Screen", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Screen;
506  if ( s.compare( "Dodge", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_ColorDodge;
507  if ( s.compare( "Addition", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Plus;
508  if ( s.compare( "Darken", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Darken;
509  if ( s.compare( "Multiply", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Multiply;
510  if ( s.compare( "Burn", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_ColorBurn;
511  if ( s.compare( "Overlay", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Overlay;
512  if ( s.compare( "SoftLight", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_SoftLight;
513  if ( s.compare( "HardLight", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_HardLight;
514  if ( s.compare( "Difference", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Difference;
515  if ( s.compare( "Subtract", Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Exclusion;
516  return QPainter::CompositionMode_SourceOver; // "Normal"
517 }
518 
520 {
521  return QIcon( symbolPreviewPixmap( symbol, size ) );
522 }
523 
525 {
526  Q_ASSERT( symbol );
527 
528  QPixmap pixmap( size );
529  pixmap.fill( Qt::transparent );
530  QPainter painter;
531  painter.begin( &pixmap );
532  painter.setRenderHint( QPainter::Antialiasing );
533  symbol->drawPreviewIcon( &painter, size );
534  painter.end();
535  return pixmap;
536 }
537 
539 {
540  double maxBleed = 0;
541  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
542  {
543  QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
544  double layerMaxBleed = layer->estimateMaxBleed();
545  maxBleed = layerMaxBleed > maxBleed ? layerMaxBleed : maxBleed;
546  }
547 
548  return maxBleed;
549 }
550 
552 {
553  QPixmap pixmap( size );
554  pixmap.fill( Qt::transparent );
555  QPainter painter;
556  painter.begin( &pixmap );
557  painter.setRenderHint( QPainter::Antialiasing );
558  QgsRenderContext renderContext = createRenderContext( &painter );
559  QgsSymbolV2RenderContext symbolContext( renderContext, u, 1.0, false, 0, 0, 0, scale );
560  layer->drawPreviewIcon( symbolContext, size );
561  painter.end();
562  return QIcon( pixmap );
563 }
564 
566 {
567  return QIcon( colorRampPreviewPixmap( ramp, size ) );
568 }
569 
571 {
572  QPixmap pixmap( size );
573  pixmap.fill( Qt::transparent );
574  // pixmap.fill( Qt::white ); // this makes the background white instead of transparent
575  QPainter painter;
576  painter.begin( &pixmap );
577 
578  //draw stippled background, for transparent images
579  drawStippledBackround( &painter, QRect( 0, 0, size.width(), size.height() ) );
580 
581  // antialising makes the colors duller, and no point in antialiasing a color ramp
582  // painter.setRenderHint( QPainter::Antialiasing );
583  for ( int i = 0; i < size.width(); i++ )
584  {
585  QPen pen( ramp->color(( double ) i / size.width() ) );
586  painter.setPen( pen );
587  painter.drawLine( i, 0, i, size.height() - 1 );
588  }
589  painter.end();
590  return pixmap;
591 }
592 
593 void QgsSymbolLayerV2Utils::drawStippledBackround( QPainter* painter, QRect rect )
594 {
595  // create a 2x2 checker-board image
596  uchar pixDataRGB[] = { 255, 255, 255, 255,
597  127, 127, 127, 255,
598  127, 127, 127, 255,
599  255, 255, 255, 255
600  };
601  QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
602  // scale it to rect so at least 5 patterns are shown
603  int width = ( rect.width() < rect.height() ) ?
604  rect.width() / 2.5 : rect.height() / 2.5;
605  QPixmap pix = QPixmap::fromImage( img.scaled( width, width ) );
606  // fill rect with texture
607  QBrush brush;
608  brush.setTexture( pix );
609  painter->fillRect( rect, brush );
610 }
611 
612 #include <QPolygonF>
613 
614 #include <cmath>
615 #include <cfloat>
616 
617 
618 #if !defined(GEOS_VERSION_MAJOR) || !defined(GEOS_VERSION_MINOR) || \
619  ((GEOS_VERSION_MAJOR<3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR<3)))
620 // calculate line's angle and tangent
621 static bool lineInfo( QPointF p1, QPointF p2, double& angle, double& t )
622 {
623  double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();
624 
625  if ( x1 == x2 && y1 == y2 )
626  return false;
627 
628  // tangent
629  t = ( x1 == x2 ? DBL_MAX : ( y2 - y1 ) / ( x2 - x1 ) );
630 
631  // angle
632  if ( t == DBL_MAX )
633  angle = ( y2 > y1 ? M_PI / 2 : M_PI * 3 / 2 ); // angle is 90 or 270
634  else if ( t == 0 )
635  angle = ( x2 > x1 ? 0 : M_PI ); // angle is 0 or 180
636  else if ( t >= 0 )
637  angle = ( y2 > y1 ? atan( t ) : M_PI + atan( t ) );
638  else // t < 0
639  angle = ( y2 > y1 ? M_PI + atan( t ) : atan( t ) );
640 
641  return true;
642 }
643 
644 // offset a point with an angle and distance
645 static QPointF offsetPoint( QPointF pt, double angle, double dist )
646 {
647  return QPointF( pt.x() + dist * cos( angle ), pt.y() + dist * sin( angle ) );
648 }
649 
650 // calc intersection of two (infinite) lines defined by one point and tangent
651 static QPointF linesIntersection( QPointF p1, double t1, QPointF p2, double t2 )
652 {
653  // parallel lines? (or the difference between angles is less than appr. 10 degree)
654  if (( t1 == DBL_MAX && t2 == DBL_MAX ) || qAbs( atan( t1 ) - atan( t2 ) ) < 0.175 )
655  return QPointF();
656 
657  double x, y;
658  if ( t1 == DBL_MAX || t2 == DBL_MAX )
659  {
660  // in case one line is with angle 90 resp. 270 degrees (tangent undefined)
661  // swap them so that line 2 is with undefined tangent
662  if ( t1 == DBL_MAX )
663  {
664  QPointF pSwp = p1; p1 = p2; p2 = pSwp;
665  double tSwp = t1; t1 = t2; t2 = tSwp;
666  }
667 
668  x = p2.x();
669  }
670  else
671  {
672  // usual case
673  x = (( p1.y() - p2.y() ) + t2 * p2.x() - t1 * p1.x() ) / ( t2 - t1 );
674  }
675 
676  y = p1.y() + t1 * ( x - p1.x() );
677  return QPointF( x, y );
678 }
679 #else
680 static QPolygonF makeOffsetGeometry( const QgsPolyline& polyline )
681 {
682  int i, pointCount = polyline.count();
683 
684  QPolygonF resultLine;
685  resultLine.resize( pointCount );
686 
687  const QgsPoint* tempPtr = polyline.data();
688 
689  for ( i = 0; i < pointCount; ++i, tempPtr++ )
690  resultLine[i] = QPointF( tempPtr->x(), tempPtr->y() );
691 
692  return resultLine;
693 }
694 static QList<QPolygonF> makeOffsetGeometry( const QgsPolygon& polygon )
695 {
696  QList<QPolygonF> resultGeom;
697  for ( int ring = 0; ring < polygon.size(); ++ring ) resultGeom.append( makeOffsetGeometry( polygon[ ring ] ) );
698  return resultGeom;
699 }
700 #endif
701 
702 QList<QPolygonF> offsetLine( QPolygonF polyline, double dist, QGis::GeometryType geometryType )
703 {
704  QList<QPolygonF> resultLine;
705 
706  if ( polyline.count() < 2 )
707  {
708  resultLine.append( polyline );
709  return resultLine;
710  }
711 
712  QPolygonF newLine;
713 
714  // need at least geos 3.3 for OffsetCurve tool
715 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
716  ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3)))
717 
718  unsigned int i, pointCount = polyline.count();
719 
720  QgsPolyline tempPolyline( pointCount );
721  QPointF* tempPtr = polyline.data();
722  for ( i = 0; i < pointCount; ++i, tempPtr++ )
723  tempPolyline[i] = QgsPoint( tempPtr->rx(), tempPtr->ry() );
724 
725  QgsGeometry* tempGeometry = ( geometryType == QGis::Polygon ) ? QgsGeometry::fromPolygon( QgsPolygon() << tempPolyline ) : QgsGeometry::fromPolyline( tempPolyline );
726  if ( tempGeometry )
727  {
728  int quadSegments = 0; // we want mitre joins, not round joins
729  double mitreLimit = 2.0; // the default value in GEOS (5.0) allows for fairly sharp endings
730  QgsGeometry* offsetGeom = 0;
731  if ( geometryType == QGis::Polygon )
732  offsetGeom = tempGeometry->buffer( -dist, quadSegments, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_MITRE, mitreLimit );
733  else
734  offsetGeom = tempGeometry->offsetCurve( dist, quadSegments, GEOSBUF_JOIN_MITRE, mitreLimit );
735 
736  if ( offsetGeom )
737  {
738  delete tempGeometry;
739  tempGeometry = offsetGeom;
740 
741  if ( QGis::flatType( tempGeometry->wkbType() ) == QGis::WKBLineString )
742  {
743  resultLine.append( makeOffsetGeometry( tempGeometry->asPolyline() ) );
744  delete tempGeometry;
745  return resultLine;
746  }
747  else if ( QGis::flatType( tempGeometry->wkbType() ) == QGis::WKBPolygon )
748  {
749  resultLine.append( makeOffsetGeometry( tempGeometry->asPolygon() ) );
750  delete tempGeometry;
751  return resultLine;
752  }
753  else if ( QGis::flatType( tempGeometry->wkbType() ) == QGis::WKBMultiLineString )
754  {
755  QgsMultiPolyline tempMPolyline = tempGeometry->asMultiPolyline();
756 
757  for ( int part = 0; part < tempMPolyline.count(); ++part )
758  {
759  resultLine.append( makeOffsetGeometry( tempMPolyline[ part ] ) );
760  }
761  delete tempGeometry;
762  return resultLine;
763  }
764  else if ( QGis::flatType( tempGeometry->wkbType() ) == QGis::WKBMultiPolygon )
765  {
766  QgsMultiPolygon tempMPolygon = tempGeometry->asMultiPolygon();
767 
768  for ( int part = 0; part < tempMPolygon.count(); ++part )
769  {
770  resultLine.append( makeOffsetGeometry( tempMPolygon[ part ] ) );
771  }
772  delete tempGeometry;
773  return resultLine;
774  }
775  }
776  delete tempGeometry;
777  }
778 
779  // returns original polyline when 'GEOSOffsetCurve' fails!
780  resultLine.append( polyline );
781  return resultLine;
782 
783 #else
784 
785  double angle = 0.0, t_new, t_old = 0;
786  QPointF pt_old, pt_new;
787  QPointF p1 = polyline[0], p2;
788  bool first_point = true;
789 
790  for ( int i = 1; i < polyline.count(); i++ )
791  {
792  p2 = polyline[i];
793 
794  if ( !lineInfo( p1, p2, angle, t_new ) )
795  continue; // not a line...
796 
797  pt_new = offsetPoint( p1, angle + M_PI / 2, dist );
798 
799  if ( ! first_point )
800  {
801  // if it's not the first line segment
802  // calc intersection with last line (with offset)
803  QPointF pt_tmp = linesIntersection( pt_old, t_old, pt_new, t_new );
804  if ( !pt_tmp.isNull() )
805  pt_new = pt_tmp;
806  }
807 
808  newLine.append( pt_new );
809 
810  pt_old = pt_new;
811  t_old = t_new;
812  p1 = p2;
813  first_point = false;
814  }
815 
816  // last line segment:
817  pt_new = offsetPoint( p2, angle + M_PI / 2, dist );
818  newLine.append( pt_new );
819 
820  resultLine.append( newLine );
821  return resultLine;
822 
823 #endif
824 }
825 QList<QPolygonF> offsetLine( QPolygonF polyline, double dist )
826 {
827  QGis::GeometryType geometryType = QGis::Point;
828  int pointCount = polyline.count();
829 
830  if ( pointCount > 3 && polyline[ 0 ].x() == polyline[ pointCount - 1 ].x() && polyline[ 0 ].y() == polyline[ pointCount - 1 ].y() )
831  {
832  geometryType = QGis::Polygon;
833  }
834  else if ( pointCount > 1 )
835  {
836  geometryType = QGis::Line;
837  }
838  return offsetLine( polyline, dist, geometryType );
839 }
840 
842 
843 
845 {
846  QgsSymbolLayerV2List layers;
847  QDomNode layerNode = element.firstChild();
848 
849  while ( !layerNode.isNull() )
850  {
851  QDomElement e = layerNode.toElement();
852  if ( !e.isNull() )
853  {
854  if ( e.tagName() != "layer" )
855  {
856  QgsDebugMsg( "unknown tag " + e.tagName() );
857  }
858  else
859  {
860  QgsSymbolLayerV2* layer = loadSymbolLayer( e );
861 
862  if ( layer != NULL )
863  {
864  // Dealing with sub-symbols nested into a layer
865  QDomElement s = e.firstChildElement( "symbol" );
866  if ( !s.isNull() )
867  {
868  QgsSymbolV2* subSymbol = loadSymbol( s );
869  bool res = layer->setSubSymbol( subSymbol );
870  if ( !res )
871  {
872  QgsDebugMsg( "symbol layer refused subsymbol: " + s.attribute( "name" ) );
873  }
874  }
875  layers.append( layer );
876  }
877  }
878  }
879  layerNode = layerNode.nextSibling();
880  }
881 
882  if ( layers.count() == 0 )
883  {
884  QgsDebugMsg( "no layers for symbol" );
885  return NULL;
886  }
887 
888  QString symbolType = element.attribute( "type" );
889 
890  QgsSymbolV2* symbol = 0;
891  if ( symbolType == "line" )
892  symbol = new QgsLineSymbolV2( layers );
893  else if ( symbolType == "fill" )
894  symbol = new QgsFillSymbolV2( layers );
895  else if ( symbolType == "marker" )
896  symbol = new QgsMarkerSymbolV2( layers );
897  else
898  {
899  QgsDebugMsg( "unknown symbol type " + symbolType );
900  return NULL;
901  }
902 
903  if ( element.hasAttribute( "outputUnit" ) )
904  {
905  symbol->setOutputUnit( decodeOutputUnit( element.attribute( "outputUnit" ) ) );
906  }
907  if ( element.hasAttribute(( "mapUnitScale" ) ) )
908  {
909  QgsMapUnitScale mapUnitScale;
910  mapUnitScale.minScale = element.attribute( "mapUnitMinScale", "0.0" ).toDouble();
911  mapUnitScale.maxScale = element.attribute( "mapUnitMaxScale", "0.0" ).toDouble();
912  symbol->setMapUnitScale( mapUnitScale );
913  }
914  symbol->setAlpha( element.attribute( "alpha", "1.0" ).toDouble() );
915 
916  return symbol;
917 }
918 
920 {
921  QString layerClass = element.attribute( "class" );
922  bool locked = element.attribute( "locked" ).toInt();
923  int pass = element.attribute( "pass" ).toInt();
924 
925  // parse properties
926  QgsStringMap props = parseProperties( element );
927 
928  QgsSymbolLayerV2* layer;
929  layer = QgsSymbolLayerV2Registry::instance()->createSymbolLayer( layerClass, props );
930  if ( layer )
931  {
932  layer->setLocked( locked );
933  layer->setRenderingPass( pass );
934  return layer;
935  }
936  else
937  {
938  QgsDebugMsg( "unknown class " + layerClass );
939  return NULL;
940  }
941 }
942 
944 {
945  switch ( type )
946  {
947  case QgsSymbolV2::Line: return "line";
948  case QgsSymbolV2::Marker: return "marker";
949  case QgsSymbolV2::Fill: return "fill";
950  default: return "";
951  }
952 }
953 
954 QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc )
955 {
956  Q_ASSERT( symbol );
957  QDomElement symEl = doc.createElement( "symbol" );
958  symEl.setAttribute( "type", _nameForSymbolType( symbol->type() ) );
959  symEl.setAttribute( "name", name );
960  symEl.setAttribute( "alpha", QString::number( symbol->alpha() ) );
961  QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
962 
963  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
964  {
965  QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
966 
967  QDomElement layerEl = doc.createElement( "layer" );
968  layerEl.setAttribute( "class", layer->layerType() );
969  layerEl.setAttribute( "locked", layer->isLocked() );
970  layerEl.setAttribute( "pass", layer->renderingPass() );
971  saveProperties( layer->properties(), doc, layerEl );
972  if ( layer->subSymbol() != NULL )
973  {
974  QString subname = QString( "@%1@%2" ).arg( name ).arg( i );
975  QDomElement subEl = saveSymbol( subname, layer->subSymbol(), doc );
976  layerEl.appendChild( subEl );
977  }
978  symEl.appendChild( layerEl );
979  }
980 
981  return symEl;
982 }
983 
984 
986  QGis::GeometryType geomType,
987  QgsSymbolLayerV2List &layers )
988 {
989  QgsDebugMsg( "Entered." );
990 
991  if ( element.isNull() )
992  return false;
993 
994  QgsSymbolLayerV2 *l = 0;
995 
996  QString symbolizerName = element.localName();
997 
998  if ( symbolizerName == "PointSymbolizer" )
999  {
1000  // first check for Graphic element, nothing will be rendered if not found
1001  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1002  if ( graphicElem.isNull() )
1003  {
1004  QgsDebugMsg( "Graphic element not found in PointSymbolizer" );
1005  }
1006  else
1007  {
1008  switch ( geomType )
1009  {
1010  case QGis::Polygon:
1011  // polygon layer and point symbolizer: draw poligon centroid
1012  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "CentroidFill", element );
1013  if ( l )
1014  layers.append( l );
1015 
1016  break;
1017 
1018  case QGis::Point:
1019  // point layer and point symbolizer: use markers
1020  l = createMarkerLayerFromSld( element );
1021  if ( l )
1022  layers.append( l );
1023 
1024  break;
1025 
1026  case QGis::Line:
1027  // line layer and point symbolizer: draw central point
1028  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
1029  if ( l )
1030  layers.append( l );
1031 
1032  break;
1033 
1034  default:
1035  break;
1036  }
1037  }
1038  }
1039 
1040  if ( symbolizerName == "LineSymbolizer" )
1041  {
1042  // check for Stroke element, nothing will be rendered if not found
1043  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1044  if ( strokeElem.isNull() )
1045  {
1046  QgsDebugMsg( "Stroke element not found in LineSymbolizer" );
1047  }
1048  else
1049  {
1050  switch ( geomType )
1051  {
1052  case QGis::Polygon:
1053  case QGis::Line:
1054  // polygon layer and line symbolizer: draw polygon outline
1055  // line layer and line symbolizer: draw line
1056  l = createLineLayerFromSld( element );
1057  if ( l )
1058  layers.append( l );
1059 
1060  break;
1061 
1062  case QGis::Point:
1063  // point layer and line symbolizer: draw a little line marker
1064  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
1065  if ( l )
1066  layers.append( l );
1067 
1068  default:
1069  break;
1070  }
1071  }
1072  }
1073 
1074  if ( symbolizerName == "PolygonSymbolizer" )
1075  {
1076  // get Fill and Stroke elements, nothing will be rendered if both are missing
1077  QDomElement fillElem = element.firstChildElement( "Fill" );
1078  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1079  if ( fillElem.isNull() && strokeElem.isNull() )
1080  {
1081  QgsDebugMsg( "neither Fill nor Stroke element not found in PolygonSymbolizer" );
1082  }
1083  else
1084  {
1085  QgsSymbolLayerV2 *l = 0;
1086 
1087  switch ( geomType )
1088  {
1089  case QGis::Polygon:
1090  // polygon layer and polygon symbolizer: draw fill
1091 
1092  l = createFillLayerFromSld( element );
1093  if ( l )
1094  {
1095  layers.append( l );
1096 
1097  // SVGFill and SimpleFill symbolLayerV2 supports outline internally,
1098  // so don't go forward to create a different symbolLayerV2 for outline
1099  if ( l->layerType() == "SimpleFill" || l->layerType() == "SVGFill" )
1100  break;
1101  }
1102 
1103  // now create polygon outline
1104  // polygon layer and polygon symbolizer: draw polygon outline
1105  l = createLineLayerFromSld( element );
1106  if ( l )
1107  layers.append( l );
1108 
1109  break;
1110 
1111  case QGis::Line:
1112  // line layer and polygon symbolizer: draw line
1113  l = createLineLayerFromSld( element );
1114  if ( l )
1115  layers.append( l );
1116 
1117  break;
1118 
1119  case QGis::Point:
1120  // point layer and polygon symbolizer: draw a square marker
1121  convertPolygonSymbolizerToPointMarker( element, layers );
1122  break;
1123 
1124  default:
1125  break;
1126  }
1127  }
1128  }
1129 
1130  return true;
1131 }
1132 
1134 {
1135  QDomElement fillElem = element.firstChildElement( "Fill" );
1136  if ( fillElem.isNull() )
1137  {
1138  QgsDebugMsg( "Fill element not found" );
1139  return NULL;
1140  }
1141 
1142  QgsSymbolLayerV2 *l = 0;
1143 
1144  if ( needLinePatternFill( element ) )
1145  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "LinePatternFill", element );
1146  else if ( needPointPatternFill( element ) )
1147  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "PointPatternFill", element );
1148  else if ( needSvgFill( element ) )
1149  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SVGFill", element );
1150  else
1151  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleFill", element );
1152 
1153  return l;
1154 }
1155 
1157 {
1158  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1159  if ( strokeElem.isNull() )
1160  {
1161  QgsDebugMsg( "Stroke element not found" );
1162  return NULL;
1163  }
1164 
1165  QgsSymbolLayerV2 *l = 0;
1166 
1167  if ( needMarkerLine( element ) )
1168  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
1169  else
1170  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleLine", element );
1171 
1172  return l;
1173 }
1174 
1176 {
1177  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1178  if ( graphicElem.isNull() )
1179  {
1180  QgsDebugMsg( "Graphic element not found" );
1181  return NULL;
1182  }
1183 
1184  QgsSymbolLayerV2 *l = 0;
1185 
1186  if ( needFontMarker( element ) )
1187  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "FontMarker", element );
1188  else if ( needSvgMarker( element ) )
1189  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SvgMarker", element );
1190  else if ( needEllipseMarker( element ) )
1191  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "EllipseMarker", element );
1192  else
1193  l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
1194 
1195  return l;
1196 }
1197 
1198 bool QgsSymbolLayerV2Utils::hasExternalGraphic( QDomElement &element )
1199 {
1200  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1201  if ( graphicElem.isNull() )
1202  return false;
1203 
1204  QDomElement externalGraphicElem = graphicElem.firstChildElement( "ExternalGraphic" );
1205  if ( externalGraphicElem.isNull() )
1206  return false;
1207 
1208  // check for format
1209  QDomElement formatElem = externalGraphicElem.firstChildElement( "Format" );
1210  if ( formatElem.isNull() )
1211  return false;
1212 
1213  QString format = formatElem.firstChild().nodeValue();
1214  if ( format != "image/svg+xml" )
1215  {
1216  QgsDebugMsg( "unsupported External Graphic format found: " + format );
1217  return false;
1218  }
1219 
1220  // check for a valid content
1221  QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( "OnlineResource" );
1222  QDomElement inlineContentElem = externalGraphicElem.firstChildElement( "InlineContent" );
1223  if ( !onlineResourceElem.isNull() )
1224  {
1225  return true;
1226  }
1227 #if 0
1228  else if ( !inlineContentElem.isNull() )
1229  {
1230  return false; // not implemented yet
1231  }
1232 #endif
1233  else
1234  {
1235  return false;
1236  }
1237 }
1238 
1239 bool QgsSymbolLayerV2Utils::hasWellKnownMark( QDomElement &element )
1240 {
1241  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1242  if ( graphicElem.isNull() )
1243  return false;
1244 
1245  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
1246  if ( markElem.isNull() )
1247  return false;
1248 
1249  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
1250  if ( wellKnownNameElem.isNull() )
1251  return false;
1252 
1253  return true;
1254 }
1255 
1256 
1257 bool QgsSymbolLayerV2Utils::needFontMarker( QDomElement &element )
1258 {
1259  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1260  if ( graphicElem.isNull() )
1261  return false;
1262 
1263  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
1264  if ( markElem.isNull() )
1265  return false;
1266 
1267  // check for format
1268  QDomElement formatElem = markElem.firstChildElement( "Format" );
1269  if ( formatElem.isNull() )
1270  return false;
1271 
1272  QString format = formatElem.firstChild().nodeValue();
1273  if ( format != "ttf" )
1274  {
1275  QgsDebugMsg( "unsupported Graphic Mark format found: " + format );
1276  return false;
1277  }
1278 
1279  // check for a valid content
1280  QDomElement onlineResourceElem = markElem.firstChildElement( "OnlineResource" );
1281  QDomElement inlineContentElem = markElem.firstChildElement( "InlineContent" );
1282  if ( !onlineResourceElem.isNull() )
1283  {
1284  // mark with ttf format has a markIndex element
1285  QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
1286  if ( !markIndexElem.isNull() )
1287  return true;
1288  }
1289  else if ( !inlineContentElem.isNull() )
1290  {
1291  return false; // not implemented yet
1292  }
1293 
1294  return false;
1295 }
1296 
1297 bool QgsSymbolLayerV2Utils::needSvgMarker( QDomElement &element )
1298 {
1299  return hasExternalGraphic( element );
1300 }
1301 
1302 bool QgsSymbolLayerV2Utils::needEllipseMarker( QDomElement &element )
1303 {
1304  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1305  if ( graphicElem.isNull() )
1306  return false;
1307 
1308  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
1309  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1310  {
1311  if ( it.key() == "widthHeightFactor" )
1312  {
1313  return true;
1314  }
1315  }
1316 
1317  return false;
1318 }
1319 
1320 bool QgsSymbolLayerV2Utils::needMarkerLine( QDomElement &element )
1321 {
1322  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1323  if ( strokeElem.isNull() )
1324  return false;
1325 
1326  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1327  if ( graphicStrokeElem.isNull() )
1328  return false;
1329 
1330  return hasWellKnownMark( graphicStrokeElem );
1331 }
1332 
1334 {
1335  QDomElement fillElem = element.firstChildElement( "Fill" );
1336  if ( fillElem.isNull() )
1337  return false;
1338 
1339  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1340  if ( graphicFillElem.isNull() )
1341  return false;
1342 
1343  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1344  if ( graphicElem.isNull() )
1345  return false;
1346 
1347  // line pattern fill uses horline wellknown marker with an angle
1348 
1349  QString name;
1350  QColor fillColor, borderColor;
1351  double size, borderWidth;
1352  Qt::PenStyle borderStyle;
1353  if ( !wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
1354  return false;
1355 
1356  if ( name != "horline" )
1357  return false;
1358 
1359  QString angleFunc;
1360  if ( !rotationFromSldElement( graphicElem, angleFunc ) )
1361  return false;
1362 
1363  bool ok;
1364  double angle = angleFunc.toDouble( &ok );
1365  if ( !ok || angle == 0 )
1366  return false;
1367 
1368  return true;
1369 }
1370 
1372 {
1373  Q_UNUSED( element );
1374  return false;
1375 }
1376 
1377 bool QgsSymbolLayerV2Utils::needSvgFill( QDomElement &element )
1378 {
1379  QDomElement fillElem = element.firstChildElement( "Fill" );
1380  if ( fillElem.isNull() )
1381  return false;
1382 
1383  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1384  if ( graphicFillElem.isNull() )
1385  return false;
1386 
1387  return hasExternalGraphic( graphicFillElem );
1388 }
1389 
1390 
1392 {
1393  QgsDebugMsg( "Entered." );
1394 
1395  /* SE 1.1 says about PolygonSymbolizer:
1396  if a point geometry is referenced instead of a polygon,
1397  then a small, square, ortho-normal polygon should be
1398  constructed for rendering.
1399  */
1400 
1401  QgsSymbolLayerV2List layers;
1402 
1403  // retrieve both Fill and Stroke elements
1404  QDomElement fillElem = element.firstChildElement( "Fill" );
1405  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1406 
1407  // first symbol layer
1408  {
1409  bool validFill = false, validBorder = false;
1410 
1411  // check for simple fill
1412  // Fill element can contain some SvgParameter elements
1413  QColor fillColor;
1414  Qt::BrushStyle fillStyle;
1415 
1416  if ( fillFromSld( fillElem, fillStyle, fillColor ) )
1417  validFill = true;
1418 
1419  // check for simple outline
1420  // Stroke element can contain some SvgParameter elements
1421  QColor borderColor;
1422  Qt::PenStyle borderStyle;
1423  double borderWidth = 1.0, dashOffset = 0.0;
1424  QVector<qreal> customDashPattern;
1425 
1426  if ( lineFromSld( strokeElem, borderStyle, borderColor, borderWidth,
1427  0, 0, &customDashPattern, &dashOffset ) )
1428  validBorder = true;
1429 
1430  if ( validFill || validBorder )
1431  {
1432  QgsStringMap map;
1433  map["name"] = "square";
1434  map["color"] = encodeColor( validFill ? fillColor : Qt::transparent );
1435  map["color_border"] = encodeColor( validBorder ? borderColor : Qt::transparent );
1436  map["size"] = QString::number( 6 );
1437  map["angle"] = QString::number( 0 );
1438  map["offset"] = encodePoint( QPointF( 0, 0 ) );
1439  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SimpleMarker", map ) );
1440  }
1441  }
1442 
1443  // second symbol layer
1444  {
1445  bool validFill = false, validBorder = false;
1446 
1447  // check for graphic fill
1448  QString name, format;
1449  int markIndex = -1;
1450  QColor fillColor, borderColor;
1451  double borderWidth = 1.0, size = 0.0, angle = 0.0;
1452  QPointF anchor, offset;
1453 
1454  // Fill element can contain a GraphicFill element
1455  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1456  if ( !graphicFillElem.isNull() )
1457  {
1458  // GraphicFill element must contain a Graphic element
1459  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1460  if ( !graphicElem.isNull() )
1461  {
1462  // Graphic element can contains some ExternalGraphic and Mark element
1463  // search for the first supported one and use it
1464  bool found = false;
1465 
1466  QDomElement graphicChildElem = graphicElem.firstChildElement();
1467  while ( !graphicChildElem.isNull() )
1468  {
1469  if ( graphicChildElem.localName() == "Mark" )
1470  {
1471  // check for a well known name
1472  QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( "WellKnownName" );
1473  if ( !wellKnownNameElem.isNull() )
1474  {
1475  name = wellKnownNameElem.firstChild().nodeValue();
1476  found = true;
1477  break;
1478  }
1479  }
1480 
1481  if ( graphicChildElem.localName() == "ExternalGraphic" || graphicChildElem.localName() == "Mark" )
1482  {
1483  // check for external graphic format
1484  QDomElement formatElem = graphicChildElem.firstChildElement( "Format" );
1485  if ( formatElem.isNull() )
1486  continue;
1487 
1488  format = formatElem.firstChild().nodeValue();
1489 
1490  // TODO: remove this check when more formats will be supported
1491  // only SVG external graphics are supported in this moment
1492  if ( graphicChildElem.localName() == "ExternalGraphic" && format != "image/svg+xml" )
1493  continue;
1494 
1495  // TODO: remove this check when more formats will be supported
1496  // only ttf marks are supported in this moment
1497  if ( graphicChildElem.localName() == "Mark" && format != "ttf" )
1498  continue;
1499 
1500  // check for a valid content
1501  QDomElement onlineResourceElem = graphicChildElem.firstChildElement( "OnlineResource" );
1502  QDomElement inlineContentElem = graphicChildElem.firstChildElement( "InlineContent" );
1503 
1504  if ( !onlineResourceElem.isNull() )
1505  {
1506  name = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
1507 
1508  if ( graphicChildElem.localName() == "Mark" && format == "ttf" )
1509  {
1510  // mark with ttf format may have a name like ttf://fontFamily
1511  if ( name.startsWith( "ttf://" ) )
1512  name = name.mid( 6 );
1513 
1514  // mark with ttf format has a markIndex element
1515  QDomElement markIndexElem = graphicChildElem.firstChildElement( "MarkIndex" );
1516  if ( markIndexElem.isNull() )
1517  continue;
1518 
1519  bool ok;
1520  int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
1521  if ( !ok || v < 0 )
1522  continue;
1523 
1524  markIndex = v;
1525  }
1526 
1527  found = true;
1528  break;
1529  }
1530 #if 0
1531  else if ( !inlineContentElem.isNull() )
1532  continue; // TODO: not implemented yet
1533 #endif
1534  else
1535  continue;
1536  }
1537 
1538  // if Mark element is present but it doesn't contains neither
1539  // WellKnownName nor OnlineResource nor InlineContent,
1540  // use the default mark (square)
1541  if ( graphicChildElem.localName() == "Mark" )
1542  {
1543  name = "square";
1544  found = true;
1545  break;
1546  }
1547  }
1548 
1549  // if found a valid Mark, check for its Fill and Stroke element
1550  if ( found && graphicChildElem.localName() == "Mark" )
1551  {
1552  // XXX: recursive definition!?! couldn't be dangerous???
1553  // to avoid recursion we handle only simple fill and simple stroke
1554 
1555  // check for simple fill
1556  // Fill element can contain some SvgParameter elements
1557  Qt::BrushStyle markFillStyle;
1558 
1559  QDomElement markFillElem = graphicChildElem.firstChildElement( "Fill" );
1560  if ( fillFromSld( markFillElem, markFillStyle, fillColor ) )
1561  validFill = true;
1562 
1563  // check for simple outline
1564  // Stroke element can contain some SvgParameter elements
1565  Qt::PenStyle borderStyle;
1566  double borderWidth = 1.0, dashOffset = 0.0;
1567  QVector<qreal> customDashPattern;
1568 
1569  QDomElement markStrokeElem = graphicChildElem.firstChildElement( "Stroke" );
1570  if ( lineFromSld( markStrokeElem, borderStyle, borderColor, borderWidth,
1571  0, 0, &customDashPattern, &dashOffset ) )
1572  validBorder = true;
1573  }
1574 
1575  if ( found )
1576  {
1577  // check for Opacity, Size, Rotation, AnchorPoint, Displacement
1578  QDomElement opacityElem = graphicElem.firstChildElement( "Opacity" );
1579  if ( !opacityElem.isNull() )
1580  fillColor.setAlpha( decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
1581 
1582  QDomElement sizeElem = graphicElem.firstChildElement( "Size" );
1583  if ( !sizeElem.isNull() )
1584  {
1585  bool ok;
1586  double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
1587  if ( ok && v > 0 )
1588  size = v;
1589  }
1590 
1591  QString angleFunc;
1592  if ( rotationFromSldElement( graphicElem, angleFunc ) && !angleFunc.isEmpty() )
1593  {
1594  bool ok;
1595  double v = angleFunc.toDouble( &ok );
1596  if ( ok )
1597  angle = v;
1598  }
1599 
1600  displacementFromSldElement( graphicElem, offset );
1601  }
1602  }
1603  }
1604 
1605  if ( validFill || validBorder )
1606  {
1607  if ( format == "image/svg+xml" )
1608  {
1609  QgsStringMap map;
1610  map["name"] = name;
1611  map["fill"] = fillColor.name();
1612  map["outline"] = borderColor.name();
1613  map["outline-width"] = QString::number( borderWidth );
1614  if ( !qgsDoubleNear( size, 0.0 ) )
1615  map["size"] = QString::number( size );
1616  if ( !qgsDoubleNear( angle, 0.0 ) )
1617  map["angle"] = QString::number( angle );
1618  if ( !offset.isNull() )
1619  map["offset"] = encodePoint( offset );
1620  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SvgMarker", map ) );
1621  }
1622  else if ( format == "ttf" )
1623  {
1624  QgsStringMap map;
1625  map["font"] = name;
1626  map["chr"] = markIndex;
1627  map["color"] = encodeColor( validFill ? fillColor : Qt::transparent );
1628  if ( size > 0 )
1629  map["size"] = QString::number( size );
1630  if ( !qgsDoubleNear( angle, 0.0 ) )
1631  map["angle"] = QString::number( angle );
1632  if ( !offset.isNull() )
1633  map["offset"] = encodePoint( offset );
1634  layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "FontMarker", map ) );
1635  }
1636  }
1637  }
1638 
1639  if ( layers.isEmpty() )
1640  return false;
1641 
1642  layerList << layers;
1643  layers.clear();
1644  return true;
1645 }
1646 
1647 void QgsSymbolLayerV2Utils::fillToSld( QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color )
1648 {
1649  QString patternName;
1650  switch ( brushStyle )
1651  {
1652  case Qt::NoBrush:
1653  return;
1654 
1655  case Qt::SolidPattern:
1656  if ( color.isValid() )
1657  {
1658  element.appendChild( createSvgParameterElement( doc, "fill", color.name() ) );
1659  if ( color.alpha() < 255 )
1660  element.appendChild( createSvgParameterElement( doc, "fill-opacity", encodeSldAlpha( color.alpha() ) ) );
1661  }
1662  return;
1663 
1664  case Qt::CrossPattern:
1665  case Qt::DiagCrossPattern:
1666  case Qt::HorPattern:
1667  case Qt::VerPattern:
1668  case Qt::BDiagPattern:
1669  case Qt::FDiagPattern:
1670  case Qt::Dense1Pattern:
1671  case Qt::Dense2Pattern:
1672  case Qt::Dense3Pattern:
1673  case Qt::Dense4Pattern:
1674  case Qt::Dense5Pattern:
1675  case Qt::Dense6Pattern:
1676  case Qt::Dense7Pattern:
1677  patternName = encodeSldBrushStyle( brushStyle );
1678  break;
1679 
1680  default:
1681  element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
1682  return;
1683  }
1684 
1685  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
1686  element.appendChild( graphicFillElem );
1687 
1688  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1689  graphicFillElem.appendChild( graphicElem );
1690 
1691  QColor fillColor = patternName.startsWith( "brush://" ) ? color : QColor();
1692  QColor borderColor = !patternName.startsWith( "brush://" ) ? color : QColor();
1693 
1694  /* Use WellKnownName tag to handle QT brush styles. */
1695  wellKnownMarkerToSld( doc, graphicElem, patternName, fillColor, borderColor, Qt::SolidLine, -1, -1 );
1696 }
1697 
1698 bool QgsSymbolLayerV2Utils::fillFromSld( QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color )
1699 {
1700  QgsDebugMsg( "Entered." );
1701 
1702  brushStyle = Qt::SolidPattern;
1703  color = QColor( "#808080" );
1704 
1705  if ( element.isNull() )
1706  {
1707  brushStyle = Qt::NoBrush;
1708  color = QColor();
1709  return true;
1710  }
1711 
1712  QDomElement graphicFillElem = element.firstChildElement( "GraphicFill" );
1713  // if no GraphicFill element is found, it's a solid fill
1714  if ( graphicFillElem.isNull() )
1715  {
1716  QgsStringMap svgParams = getSvgParameterList( element );
1717  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
1718  {
1719  QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
1720 
1721  if ( it.key() == "fill" )
1722  color = QColor( it.value() );
1723  else if ( it.key() == "fill-opacity" )
1724  color.setAlpha( decodeSldAlpha( it.value() ) );
1725  }
1726  }
1727  else // wellKnown marker
1728  {
1729  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1730  if ( graphicElem.isNull() )
1731  return false; // Graphic is required within GraphicFill
1732 
1733  QString patternName = "square";
1734  QColor fillColor, borderColor;
1735  double borderWidth, size;
1736  Qt::PenStyle borderStyle;
1737  if ( !wellKnownMarkerFromSld( graphicElem, patternName, fillColor, borderColor, borderStyle, borderWidth, size ) )
1738  return false;
1739 
1740  brushStyle = decodeSldBrushStyle( patternName );
1741  if ( brushStyle == Qt::NoBrush )
1742  return false; // unable to decode brush style
1743 
1744  QColor c = patternName.startsWith( "brush://" ) ? fillColor : borderColor;
1745  if ( c.isValid() )
1746  color = c;
1747  }
1748 
1749  return true;
1750 }
1751 
1752 void QgsSymbolLayerV2Utils::lineToSld( QDomDocument &doc, QDomElement &element,
1753  Qt::PenStyle penStyle, QColor color, double width,
1754  const Qt::PenJoinStyle *penJoinStyle, const Qt::PenCapStyle *penCapStyle,
1755  const QVector<qreal> *customDashPattern, double dashOffset )
1756 {
1757  QVector<qreal> dashPattern;
1758  const QVector<qreal> *pattern = &dashPattern;
1759 
1760  if ( penStyle == Qt::CustomDashLine && !customDashPattern )
1761  {
1762  element.appendChild( doc.createComment( "WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) );
1763  penStyle = Qt::DashLine;
1764  }
1765 
1766  switch ( penStyle )
1767  {
1768  case Qt::NoPen:
1769  return;
1770 
1771  case Qt::SolidLine:
1772  break;
1773 
1774  case Qt::DashLine:
1775  dashPattern.push_back( 4.0 );
1776  dashPattern.push_back( 2.0 );
1777  break;
1778  case Qt::DotLine:
1779  dashPattern.push_back( 1.0 );
1780  dashPattern.push_back( 2.0 );
1781  break;
1782  case Qt::DashDotLine:
1783  dashPattern.push_back( 4.0 );
1784  dashPattern.push_back( 2.0 );
1785  dashPattern.push_back( 1.0 );
1786  dashPattern.push_back( 2.0 );
1787  break;
1788  case Qt::DashDotDotLine:
1789  dashPattern.push_back( 4.0 );
1790  dashPattern.push_back( 2.0 );
1791  dashPattern.push_back( 1.0 );
1792  dashPattern.push_back( 2.0 );
1793  dashPattern.push_back( 1.0 );
1794  dashPattern.push_back( 2.0 );
1795  break;
1796 
1797  case Qt::CustomDashLine:
1798  Q_ASSERT( customDashPattern );
1799  pattern = customDashPattern;
1800  break;
1801 
1802  default:
1803  element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
1804  return;
1805  }
1806 
1807  if ( color.isValid() )
1808  {
1809  element.appendChild( createSvgParameterElement( doc, "stroke", color.name() ) );
1810  if ( color.alpha() < 255 )
1811  element.appendChild( createSvgParameterElement( doc, "stroke-opacity", encodeSldAlpha( color.alpha() ) ) );
1812  }
1813  if ( width > 0 )
1814  element.appendChild( createSvgParameterElement( doc, "stroke-width", QString::number( width ) ) );
1815  if ( penJoinStyle )
1816  element.appendChild( createSvgParameterElement( doc, "stroke-linejoin", encodeSldLineJoinStyle( *penJoinStyle ) ) );
1817  if ( penCapStyle )
1818  element.appendChild( createSvgParameterElement( doc, "stroke-linecap", encodeSldLineCapStyle( *penCapStyle ) ) );
1819 
1820  if ( pattern->size() > 0 )
1821  {
1822  element.appendChild( createSvgParameterElement( doc, "stroke-dasharray", encodeSldRealVector( *pattern ) ) );
1823  if ( !qgsDoubleNear( dashOffset, 0.0 ) )
1824  element.appendChild( createSvgParameterElement( doc, "stroke-dashoffset", QString::number( dashOffset ) ) );
1825  }
1826 }
1827 
1828 
1829 bool QgsSymbolLayerV2Utils::lineFromSld( QDomElement &element,
1830  Qt::PenStyle &penStyle, QColor &color, double &width,
1831  Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
1832  QVector<qreal> *customDashPattern, double *dashOffset )
1833 {
1834  QgsDebugMsg( "Entered." );
1835 
1836  penStyle = Qt::SolidLine;
1837  color = QColor( "#000000" );
1838  width = 1;
1839  if ( penJoinStyle )
1840  *penJoinStyle = Qt::BevelJoin;
1841  if ( penCapStyle )
1842  *penCapStyle = Qt::SquareCap;
1843  if ( customDashPattern )
1844  customDashPattern->clear();
1845  if ( dashOffset )
1846  *dashOffset = 0;
1847 
1848  if ( element.isNull() )
1849  {
1850  penStyle = Qt::NoPen;
1851  color = QColor();
1852  return true;
1853  }
1854 
1855  QgsStringMap svgParams = getSvgParameterList( element );
1856  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
1857  {
1858  QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
1859 
1860  if ( it.key() == "stroke" )
1861  {
1862  color = QColor( it.value() );
1863  }
1864  else if ( it.key() == "stroke-opacity" )
1865  {
1866  color.setAlpha( decodeSldAlpha( it.value() ) );
1867  }
1868  else if ( it.key() == "stroke-width" )
1869  {
1870  bool ok;
1871  double w = it.value().toDouble( &ok );
1872  if ( ok )
1873  width = w;
1874  }
1875  else if ( it.key() == "stroke-linejoin" && penJoinStyle )
1876  {
1877  *penJoinStyle = decodeSldLineJoinStyle( it.value() );
1878  }
1879  else if ( it.key() == "stroke-linecap" && penCapStyle )
1880  {
1881  *penCapStyle = decodeSldLineCapStyle( it.value() );
1882  }
1883  else if ( it.key() == "stroke-dasharray" )
1884  {
1885  QVector<qreal> dashPattern = decodeSldRealVector( it.value() );
1886  if ( dashPattern.size() > 0 )
1887  {
1888  // convert the dasharray to one of the QT pen style,
1889  // if no match is found then set pen style to CustomDashLine
1890  bool dashPatternFound = false;
1891 
1892  if ( dashPattern.count() == 2 )
1893  {
1894  if ( dashPattern.at( 0 ) == 4.0 &&
1895  dashPattern.at( 1 ) == 2.0 )
1896  {
1897  penStyle = Qt::DashLine;
1898  dashPatternFound = true;
1899  }
1900  else if ( dashPattern.at( 0 ) == 1.0 &&
1901  dashPattern.at( 1 ) == 2.0 )
1902  {
1903  penStyle = Qt::DotLine;
1904  dashPatternFound = true;
1905  }
1906  }
1907  else if ( dashPattern.count() == 4 )
1908  {
1909  if ( dashPattern.at( 0 ) == 4.0 &&
1910  dashPattern.at( 1 ) == 2.0 &&
1911  dashPattern.at( 2 ) == 1.0 &&
1912  dashPattern.at( 3 ) == 2.0 )
1913  {
1914  penStyle = Qt::DashDotLine;
1915  dashPatternFound = true;
1916  }
1917  }
1918  else if ( dashPattern.count() == 6 )
1919  {
1920  if ( dashPattern.at( 0 ) == 4.0 &&
1921  dashPattern.at( 1 ) == 2.0 &&
1922  dashPattern.at( 2 ) == 1.0 &&
1923  dashPattern.at( 3 ) == 2.0 &&
1924  dashPattern.at( 4 ) == 1.0 &&
1925  dashPattern.at( 5 ) == 2.0 )
1926  {
1927  penStyle = Qt::DashDotDotLine;
1928  dashPatternFound = true;
1929  }
1930  }
1931 
1932  // default case: set pen style to CustomDashLine
1933  if ( !dashPatternFound )
1934  {
1935  if ( customDashPattern )
1936  {
1937  penStyle = Qt::CustomDashLine;
1938  *customDashPattern = dashPattern;
1939  }
1940  else
1941  {
1942  QgsDebugMsg( "custom dash pattern required but not provided. Using default dash pattern." );
1943  penStyle = Qt::DashLine;
1944  }
1945  }
1946  }
1947  }
1948  else if ( it.key() == "stroke-dashoffset" && dashOffset )
1949  {
1950  bool ok;
1951  double d = it.value().toDouble( &ok );
1952  if ( ok )
1953  *dashOffset = d;
1954  }
1955  }
1956 
1957  return true;
1958 }
1959 
1960 void QgsSymbolLayerV2Utils::externalGraphicToSld( QDomDocument &doc, QDomElement &element,
1961  QString path, QString mime,
1962  QColor color, double size )
1963 {
1964  QDomElement externalGraphicElem = doc.createElement( "se:ExternalGraphic" );
1965  element.appendChild( externalGraphicElem );
1966 
1967  createOnlineResourceElement( doc, externalGraphicElem, path, mime );
1968 
1969  //TODO: missing a way to handle svg color. Should use <se:ColorReplacement>
1970  Q_UNUSED( color );
1971 
1972  if ( size >= 0 )
1973  {
1974  QDomElement sizeElem = doc.createElement( "se:Size" );
1975  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
1976  element.appendChild( sizeElem );
1977  }
1978 }
1979 
1981  QString &path, QString &mime,
1982  QColor &color, double &size )
1983 {
1984  QgsDebugMsg( "Entered." );
1985  Q_UNUSED( color );
1986 
1987  QDomElement externalGraphicElem = element.firstChildElement( "ExternalGraphic" );
1988  if ( externalGraphicElem.isNull() )
1989  return false;
1990 
1991  onlineResourceFromSldElement( externalGraphicElem, path, mime );
1992 
1993  QDomElement sizeElem = element.firstChildElement( "Size" );
1994  if ( !sizeElem.isNull() )
1995  {
1996  bool ok;
1997  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
1998  if ( ok )
1999  size = s;
2000  }
2001 
2002  return true;
2003 }
2004 
2005 void QgsSymbolLayerV2Utils::externalMarkerToSld( QDomDocument &doc, QDomElement &element,
2006  QString path, QString format, int *markIndex,
2007  QColor color, double size )
2008 {
2009  QDomElement markElem = doc.createElement( "se:Mark" );
2010  element.appendChild( markElem );
2011 
2012  createOnlineResourceElement( doc, markElem, path, format );
2013 
2014  if ( markIndex )
2015  {
2016  QDomElement markIndexElem = doc.createElement( "se:MarkIndex" );
2017  markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
2018  markElem.appendChild( markIndexElem );
2019  }
2020 
2021  // <Fill>
2022  QDomElement fillElem = doc.createElement( "se:Fill" );
2023  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2024  markElem.appendChild( fillElem );
2025 
2026  // <Size>
2027  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
2028  {
2029  QDomElement sizeElem = doc.createElement( "se:Size" );
2030  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
2031  element.appendChild( sizeElem );
2032  }
2033 }
2034 
2036  QString &path, QString &format, int &markIndex,
2037  QColor &color, double &size )
2038 {
2039  QgsDebugMsg( "Entered." );
2040 
2041  color = QColor();
2042  markIndex = -1;
2043  size = -1;
2044 
2045  QDomElement markElem = element.firstChildElement( "Mark" );
2046  if ( markElem.isNull() )
2047  return false;
2048 
2049  onlineResourceFromSldElement( markElem, path, format );
2050 
2051  QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
2052  if ( !markIndexElem.isNull() )
2053  {
2054  bool ok;
2055  int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
2056  if ( ok )
2057  markIndex = i;
2058  }
2059 
2060  // <Fill>
2061  QDomElement fillElem = markElem.firstChildElement( "Fill" );
2062  Qt::BrushStyle b = Qt::SolidPattern;
2063  fillFromSld( fillElem, b, color );
2064  // ignore brush style, solid expected
2065 
2066  // <Size>
2067  QDomElement sizeElem = element.firstChildElement( "Size" );
2068  if ( !sizeElem.isNull() )
2069  {
2070  bool ok;
2071  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2072  if ( ok )
2073  size = s;
2074  }
2075 
2076  return true;
2077 }
2078 
2079 void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
2080  QString name, QColor color, QColor borderColor,
2081  double borderWidth, double size )
2082 {
2083  wellKnownMarkerToSld( doc, element, name, color, borderColor, Qt::SolidLine, borderWidth, size );
2084 }
2085 
2086 void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
2087  QString name, QColor color, QColor borderColor, Qt::PenStyle borderStyle,
2088  double borderWidth, double size )
2089 {
2090  QDomElement markElem = doc.createElement( "se:Mark" );
2091  element.appendChild( markElem );
2092 
2093  QDomElement wellKnownNameElem = doc.createElement( "se:WellKnownName" );
2094  wellKnownNameElem.appendChild( doc.createTextNode( name ) );
2095  markElem.appendChild( wellKnownNameElem );
2096 
2097  // <Fill>
2098  if ( color.isValid() )
2099  {
2100  QDomElement fillElem = doc.createElement( "se:Fill" );
2101  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2102  markElem.appendChild( fillElem );
2103  }
2104 
2105  // <Stroke>
2106  if ( borderColor.isValid() )
2107  {
2108  QDomElement strokeElem = doc.createElement( "se:Stroke" );
2109  lineToSld( doc, strokeElem, borderStyle, borderColor, borderWidth );
2110  markElem.appendChild( strokeElem );
2111  }
2112 
2113  // <Size>
2114  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
2115  {
2116  QDomElement sizeElem = doc.createElement( "se:Size" );
2117  sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
2118  element.appendChild( sizeElem );
2119  }
2120 }
2121 
2123  QString &name, QColor &color, QColor &borderColor,
2124  double &borderWidth, double &size )
2125 {
2126  Qt::PenStyle borderStyle;
2127  return wellKnownMarkerFromSld( element, name, color, borderColor, borderStyle, borderWidth, size );
2128 }
2129 
2131  QString &name, QColor &color, QColor &borderColor, Qt::PenStyle &borderStyle,
2132  double &borderWidth, double &size )
2133 {
2134  QgsDebugMsg( "Entered." );
2135 
2136  name = "square";
2137  color = QColor();
2138  borderColor = QColor( "#000000" );
2139  borderWidth = 1;
2140  size = 6;
2141 
2142  QDomElement markElem = element.firstChildElement( "Mark" );
2143  if ( markElem.isNull() )
2144  return false;
2145 
2146  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
2147  if ( !wellKnownNameElem.isNull() )
2148  {
2149  name = wellKnownNameElem.firstChild().nodeValue();
2150  QgsDebugMsg( "found Mark with well known name: " + name );
2151  }
2152 
2153  // <Fill>
2154  QDomElement fillElem = markElem.firstChildElement( "Fill" );
2155  Qt::BrushStyle b = Qt::SolidPattern;
2156  fillFromSld( fillElem, b, color );
2157  // ignore brush style, solid expected
2158 
2159  // <Stroke>
2160  QDomElement strokeElem = markElem.firstChildElement( "Stroke" );
2161  lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
2162  // ignore border style, solid expected
2163 
2164  // <Size>
2165  QDomElement sizeElem = element.firstChildElement( "Size" );
2166  if ( !sizeElem.isNull() )
2167  {
2168  bool ok;
2169  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2170  if ( ok )
2171  size = s;
2172  }
2173 
2174  return true;
2175 }
2176 
2177 void QgsSymbolLayerV2Utils::createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc )
2178 {
2179  if ( !rotationFunc.isEmpty() )
2180  {
2181  QDomElement rotationElem = doc.createElement( "se:Rotation" );
2182  createFunctionElement( doc, rotationElem, rotationFunc );
2183  element.appendChild( rotationElem );
2184  }
2185 }
2186 
2187 bool QgsSymbolLayerV2Utils::rotationFromSldElement( QDomElement &element, QString &rotationFunc )
2188 {
2189  QDomElement rotationElem = element.firstChildElement( "Rotation" );
2190  if ( !rotationElem.isNull() )
2191  {
2192  return functionFromSldElement( rotationElem, rotationFunc );
2193  }
2194  return true;
2195 }
2196 
2197 
2198 void QgsSymbolLayerV2Utils::createOpacityElement( QDomDocument &doc, QDomElement &element, QString alphaFunc )
2199 {
2200  if ( !alphaFunc.isEmpty() )
2201  {
2202  QDomElement opacityElem = doc.createElement( "se:Opacity" );
2203  createFunctionElement( doc, opacityElem, alphaFunc );
2204  element.appendChild( opacityElem );
2205  }
2206 }
2207 
2208 bool QgsSymbolLayerV2Utils::opacityFromSldElement( QDomElement &element, QString &alphaFunc )
2209 {
2210  QDomElement opacityElem = element.firstChildElement( "Opacity" );
2211  if ( !opacityElem.isNull() )
2212  {
2213  return functionFromSldElement( opacityElem, alphaFunc );
2214  }
2215  return true;
2216 }
2217 
2218 void QgsSymbolLayerV2Utils::createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset )
2219 {
2220  if ( offset.isNull() )
2221  return;
2222 
2223  QDomElement displacementElem = doc.createElement( "se:Displacement" );
2224  element.appendChild( displacementElem );
2225 
2226  QDomElement dispXElem = doc.createElement( "se:DisplacementX" );
2227  dispXElem.appendChild( doc.createTextNode( QString::number( offset.x() ) ) );
2228 
2229  QDomElement dispYElem = doc.createElement( "se:DisplacementY" );
2230  dispYElem.appendChild( doc.createTextNode( QString::number( offset.y() ) ) );
2231 
2232  displacementElem.appendChild( dispXElem );
2233  displacementElem.appendChild( dispYElem );
2234 }
2235 
2236 bool QgsSymbolLayerV2Utils::displacementFromSldElement( QDomElement &element, QPointF &offset )
2237 {
2238  offset = QPointF( 0, 0 );
2239 
2240  QDomElement displacementElem = element.firstChildElement( "Displacement" );
2241  if ( displacementElem.isNull() )
2242  return true;
2243 
2244  QDomElement dispXElem = displacementElem.firstChildElement( "DisplacementX" );
2245  if ( !dispXElem.isNull() )
2246  {
2247  bool ok;
2248  double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
2249  if ( ok )
2250  offset.setX( offsetX );
2251  }
2252 
2253  QDomElement dispYElem = displacementElem.firstChildElement( "DisplacementY" );
2254  if ( !dispYElem.isNull() )
2255  {
2256  bool ok;
2257  double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
2258  if ( ok )
2259  offset.setY( offsetY );
2260  }
2261 
2262  return true;
2263 }
2264 
2265 void QgsSymbolLayerV2Utils::labelTextToSld( QDomDocument &doc, QDomElement &element,
2266  QString label, QFont font,
2267  QColor color, double size )
2268 {
2269  QDomElement labelElem = doc.createElement( "se:Label" );
2270  labelElem.appendChild( doc.createTextNode( label ) );
2271  element.appendChild( labelElem );
2272 
2273  QDomElement fontElem = doc.createElement( "se:Font" );
2274  element.appendChild( fontElem );
2275 
2276  fontElem.appendChild( createSvgParameterElement( doc, "font-family", font.family() ) );
2277 #if 0
2278  fontElem.appendChild( createSldParameterElement( doc, "font-style", encodeSldFontStyle( font.style() ) ) );
2279  fontElem.appendChild( createSldParameterElement( doc, "font-weight", encodeSldFontWeight( font.weight() ) ) );
2280 #endif
2281  fontElem.appendChild( createSvgParameterElement( doc, "font-size", QString::number( size ) ) );
2282 
2283  // <Fill>
2284  if ( color.isValid() )
2285  {
2286  QDomElement fillElem = doc.createElement( "Fill" );
2287  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2288  element.appendChild( fillElem );
2289  }
2290 }
2291 
2292 QString QgsSymbolLayerV2Utils::ogrFeatureStylePen( double width, double mmScaleFactor, double mapUnitScaleFactor, const QColor& c,
2293  Qt::PenJoinStyle joinStyle,
2294  Qt::PenCapStyle capStyle,
2295  double offset,
2296  const QVector<qreal>* dashPattern )
2297 {
2298  QString penStyle;
2299  penStyle.append( "PEN(" );
2300  penStyle.append( "c:" );
2301  penStyle.append( c.name() );
2302  penStyle.append( ",w:" );
2303  //dxf driver writes ground units as mm? Should probably be changed in ogr
2304  penStyle.append( QString::number( width * mmScaleFactor ) );
2305  penStyle.append( "mm" );
2306 
2307  //dash dot vector
2308  if ( dashPattern && dashPattern->size() > 0 )
2309  {
2310  penStyle.append( ",p:\"" );
2311  QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
2312  for ( ; pIt != dashPattern->constEnd(); ++pIt )
2313  {
2314  if ( pIt != dashPattern->constBegin() )
2315  {
2316  penStyle.append( " " );
2317  }
2318  penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
2319  penStyle.append( "g" );
2320  }
2321  penStyle.append( "\"" );
2322  }
2323 
2324  //cap
2325  penStyle.append( ",cap:" );
2326  switch ( capStyle )
2327  {
2328  case Qt::SquareCap:
2329  penStyle.append( "p" );
2330  break;
2331  case Qt::RoundCap:
2332  penStyle.append( "r" );
2333  break;
2334  case Qt::FlatCap:
2335  default:
2336  penStyle.append( "b" );
2337  }
2338 
2339  //join
2340  penStyle.append( ",j:" );
2341  switch ( joinStyle )
2342  {
2343  case Qt::BevelJoin:
2344  penStyle.append( "b" );
2345  break;
2346  case Qt::RoundJoin:
2347  penStyle.append( "r" );
2348  break;
2349  case Qt::MiterJoin:
2350  default:
2351  penStyle.append( "m" );
2352  }
2353 
2354  //offset
2355  if ( !qgsDoubleNear( offset, 0.0 ) )
2356  {
2357  penStyle.append( ",dp:" );
2358  penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
2359  penStyle.append( "g" );
2360  }
2361 
2362  penStyle.append( ")" );
2363  return penStyle;
2364 }
2365 
2366 QString QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( const QColor& fillColor )
2367 {
2368  QString brushStyle;
2369  brushStyle.append( "BRUSH(" );
2370  brushStyle.append( "fc:" );
2371  brushStyle.append( fillColor.name() );
2372  brushStyle.append( ")" );
2373  return brushStyle;
2374 }
2375 
2376 void QgsSymbolLayerV2Utils::createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc )
2377 {
2378  if ( geomFunc.isEmpty() )
2379  return;
2380 
2381  QDomElement geometryElem = doc.createElement( "Geometry" );
2382  element.appendChild( geometryElem );
2383 
2384  /* About using a function withing the Geometry tag.
2385  *
2386  * The SLD specification <= 1.1 is vague:
2387  * "In principle, a fixed geometry could be defined using GML or
2388  * operators could be defined for computing the geometry from
2389  * references or literals. However, using a feature property directly
2390  * is by far the most commonly useful method."
2391  *
2392  * Even if it seems that specs should take care all the possible cases,
2393  * looking at the XML schema fragment that encodes the Geometry element,
2394  * it has to be a PropertyName element:
2395  * <xsd:element name="Geometry">
2396  * <xsd:complexType>
2397  * <xsd:sequence>
2398  * <xsd:element ref="ogc:PropertyName"/>
2399  * </xsd:sequence>
2400  * </xsd:complexType>
2401  * </xsd:element>
2402  *
2403  * Anyway we will use a ogc:Function to handle geometry transformations
2404  * like offset, centroid, ...
2405  */
2406 
2407  createFunctionElement( doc, geometryElem, geomFunc );
2408 }
2409 
2410 bool QgsSymbolLayerV2Utils::geometryFromSldElement( QDomElement &element, QString &geomFunc )
2411 {
2412  QDomElement geometryElem = element.firstChildElement( "Geometry" );
2413  if ( geometryElem.isNull() )
2414  return true;
2415 
2416  return functionFromSldElement( geometryElem, geomFunc );
2417 }
2418 
2419 bool QgsSymbolLayerV2Utils::createFunctionElement( QDomDocument &doc, QDomElement &element, QString function )
2420 {
2421  // let's use QgsExpression to generate the SLD for the function
2422  QgsExpression expr( function );
2423  if ( expr.hasParserError() )
2424  {
2425  element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function ) );
2426  return false;
2427  }
2428  QDomElement filterElem = QgsOgcUtils::expressionToOgcFilter( expr, doc );
2429  if ( !filterElem.isNull() )
2430  element.appendChild( filterElem );
2431  return true;
2432 }
2433 
2434 bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QString &function )
2435 {
2436  QgsDebugMsg( "Entered." );
2437  QDomElement elem;
2438  if ( element.tagName() == "Filter" )
2439  {
2440  elem = element;
2441  }
2442  else
2443  {
2444  QDomNodeList filterNodes = element.elementsByTagName( "Filter" );
2445  if ( filterNodes.size() > 0 )
2446  {
2447  elem = filterNodes.at( 0 ).toElement();
2448  }
2449  }
2450 
2451  if ( elem.isNull() )
2452  {
2453  return false;
2454  }
2455 
2456 
2458  if ( !expr )
2459  return false;
2460 
2461  bool valid = !expr->hasParserError();
2462  if ( !valid )
2463  {
2464  QgsDebugMsg( "parser error: " + expr->parserErrorString() );
2465  }
2466  else
2467  {
2468  function = expr->expression();
2469  }
2470 
2471  delete expr;
2472  return valid;
2473 }
2474 
2475 void QgsSymbolLayerV2Utils::createOnlineResourceElement( QDomDocument &doc, QDomElement &element,
2476  QString path, QString format )
2477 {
2478  // get resource url or relative path
2479  QString url = symbolPathToName( path );
2480  QDomElement onlineResourceElem = doc.createElement( "se:OnlineResource" );
2481  onlineResourceElem.setAttribute( "xlink:type", "simple" );
2482  onlineResourceElem.setAttribute( "xlink:href", url );
2483  element.appendChild( onlineResourceElem );
2484 
2485  QDomElement formatElem = doc.createElement( "se:Format" );
2486  formatElem.appendChild( doc.createTextNode( format ) );
2487  element.appendChild( formatElem );
2488 }
2489 
2490 bool QgsSymbolLayerV2Utils::onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format )
2491 {
2492  QgsDebugMsg( "Entered." );
2493 
2494  QDomElement onlineResourceElem = element.firstChildElement( "OnlineResource" );
2495  if ( onlineResourceElem.isNull() )
2496  return false;
2497 
2498  path = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
2499 
2500  QDomElement formatElem = element.firstChildElement( "Format" );
2501  if ( formatElem.isNull() )
2502  return false; // OnlineResource requires a Format sibling element
2503 
2504  format = formatElem.firstChild().nodeValue();
2505  return true;
2506 }
2507 
2508 
2509 QDomElement QgsSymbolLayerV2Utils::createSvgParameterElement( QDomDocument &doc, QString name, QString value )
2510 {
2511  QDomElement nodeElem = doc.createElement( "se:SvgParameter" );
2512  nodeElem.setAttribute( "name", name );
2513  nodeElem.appendChild( doc.createTextNode( value ) );
2514  return nodeElem;
2515 }
2516 
2518 {
2519  QgsStringMap params;
2520 
2521  QDomElement paramElem = element.firstChildElement();
2522  while ( !paramElem.isNull() )
2523  {
2524  if ( paramElem.localName() == "SvgParameter" || paramElem.localName() == "CssParameter" )
2525  {
2526  QString name = paramElem.attribute( "name" );
2527  QString value = paramElem.firstChild().nodeValue();
2528 
2529  if ( !name.isEmpty() && !value.isEmpty() )
2530  params[ name ] = value;
2531  }
2532 
2533  paramElem = paramElem.nextSiblingElement();
2534  }
2535 
2536  return params;
2537 }
2538 
2539 QDomElement QgsSymbolLayerV2Utils::createVendorOptionElement( QDomDocument &doc, QString name, QString value )
2540 {
2541  QDomElement nodeElem = doc.createElement( "VendorOption" );
2542  nodeElem.setAttribute( "name", name );
2543  nodeElem.appendChild( doc.createTextNode( value ) );
2544  return nodeElem;
2545 }
2546 
2548 {
2549  QgsStringMap params;
2550 
2551  QDomElement paramElem = element.firstChildElement( "VendorOption" );
2552  while ( !paramElem.isNull() )
2553  {
2554  QString name = paramElem.attribute( "name" );
2555  QString value = paramElem.firstChild().nodeValue();
2556 
2557  if ( !name.isEmpty() && !value.isEmpty() )
2558  params[ name ] = value;
2559 
2560  paramElem = paramElem.nextSiblingElement( "VendorOption" );
2561  }
2562 
2563  return params;
2564 }
2565 
2566 
2568 {
2569  QgsStringMap props;
2570  QDomElement e = element.firstChildElement();
2571  while ( !e.isNull() )
2572  {
2573  if ( e.tagName() != "prop" )
2574  {
2575  QgsDebugMsg( "unknown tag " + e.tagName() );
2576  }
2577  else
2578  {
2579  QString propKey = e.attribute( "k" );
2580  QString propValue = e.attribute( "v" );
2581  props[propKey] = propValue;
2582  }
2583  e = e.nextSiblingElement();
2584  }
2585  return props;
2586 }
2587 
2588 
2589 void QgsSymbolLayerV2Utils::saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element )
2590 {
2591  for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
2592  {
2593  QDomElement propEl = doc.createElement( "prop" );
2594  propEl.setAttribute( "k", it.key() );
2595  propEl.setAttribute( "v", it.value() );
2596  element.appendChild( propEl );
2597  }
2598 }
2599 
2601 {
2602  // go through symbols one-by-one and load them
2603 
2604  QgsSymbolV2Map symbols;
2605  QDomElement e = element.firstChildElement();
2606 
2607  while ( !e.isNull() )
2608  {
2609  if ( e.tagName() == "symbol" )
2610  {
2612  if ( symbol != NULL )
2613  symbols.insert( e.attribute( "name" ), symbol );
2614  }
2615  else
2616  {
2617  QgsDebugMsg( "unknown tag: " + e.tagName() );
2618  }
2619  e = e.nextSiblingElement();
2620  }
2621 
2622 
2623  // now walk through the list of symbols and find those prefixed with @
2624  // these symbols are sub-symbols of some other symbol layers
2625  // e.g. symbol named "@foo@1" is sub-symbol of layer 1 in symbol "foo"
2626  QStringList subsymbols;
2627 
2628  for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
2629  {
2630  if ( it.key()[0] != '@' )
2631  continue;
2632 
2633  // add to array (for deletion)
2634  subsymbols.append( it.key() );
2635 
2636  QStringList parts = it.key().split( "@" );
2637  if ( parts.count() < 3 )
2638  {
2639  QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
2640  delete it.value(); // we must delete it
2641  continue; // some invalid syntax
2642  }
2643  QString symname = parts[1];
2644  int symlayer = parts[2].toInt();
2645 
2646  if ( !symbols.contains( symname ) )
2647  {
2648  QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
2649  delete it.value(); // we must delete it
2650  continue;
2651  }
2652 
2653  QgsSymbolV2* sym = symbols[symname];
2654  if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
2655  {
2656  QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
2657  delete it.value(); // we must delete it
2658  continue;
2659  }
2660 
2661  // set subsymbol takes ownership
2662  bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
2663  if ( !res )
2664  {
2665  QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
2666  }
2667 
2668 
2669  }
2670 
2671  // now safely remove sub-symbol entries (they have been already deleted or the ownership was taken away)
2672  for ( int i = 0; i < subsymbols.count(); i++ )
2673  symbols.take( subsymbols[i] );
2674 
2675  return symbols;
2676 }
2677 
2678 QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString tagName, QDomDocument& doc )
2679 {
2680  QDomElement symbolsElem = doc.createElement( tagName );
2681 
2682  // save symbols
2683  for ( QMap<QString, QgsSymbolV2*>::iterator its = symbols.begin(); its != symbols.end(); ++its )
2684  {
2685  QDomElement symEl = saveSymbol( its.key(), its.value(), doc );
2686  symbolsElem.appendChild( symEl );
2687  }
2688 
2689  return symbolsElem;
2690 }
2691 
2693 {
2694  foreach ( QString name, symbols.keys() )
2695  {
2696  delete symbols.value( name );
2697  }
2698  symbols.clear();
2699 }
2700 
2701 
2703 {
2704  QString rampType = element.attribute( "type" );
2705 
2706  // parse properties
2708 
2709  if ( rampType == "gradient" )
2710  return QgsVectorGradientColorRampV2::create( props );
2711  else if ( rampType == "random" )
2712  return QgsVectorRandomColorRampV2::create( props );
2713  else if ( rampType == "colorbrewer" )
2715  else if ( rampType == "cpt-city" )
2716  return QgsCptCityColorRampV2::create( props );
2717  else
2718  {
2719  QgsDebugMsg( "unknown colorramp type " + rampType );
2720  return NULL;
2721  }
2722 }
2723 
2724 
2725 QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc )
2726 {
2727  QDomElement rampEl = doc.createElement( "colorramp" );
2728  rampEl.setAttribute( "type", ramp->type() );
2729  rampEl.setAttribute( "name", name );
2730 
2731  QgsSymbolLayerV2Utils::saveProperties( ramp->properties(), doc, rampEl );
2732  return rampEl;
2733 }
2734 
2735 QList<QColor> QgsSymbolLayerV2Utils::parseColorList( const QString colorStr )
2736 {
2737  QList<QColor> colors;
2738 
2739  //try splitting string at commas, spaces or newlines
2740  QStringList components = colorStr.simplified().split( QRegExp( "(,|\\s)" ) );
2741  QStringList::iterator it = components.begin();
2742  for ( ; it != components.end(); ++it )
2743  {
2744  QColor result = parseColor( *it, true );
2745  if ( result.isValid() )
2746  {
2747  colors << result;
2748  }
2749  }
2750  if ( colors.length() > 0 )
2751  {
2752  return colors;
2753  }
2754 
2755  //try splitting string at commas or newlines
2756  components = colorStr.split( QRegExp( "(,|\n)" ) );
2757  it = components.begin();
2758  for ( ; it != components.end(); ++it )
2759  {
2760  QColor result = parseColor( *it, true );
2761  if ( result.isValid() )
2762  {
2763  colors << result;
2764  }
2765  }
2766  if ( colors.length() > 0 )
2767  {
2768  return colors;
2769  }
2770 
2771  //try splitting string at whitespace or newlines
2772  components = colorStr.simplified().split( QString( " " ) );
2773  it = components.begin();
2774  for ( ; it != components.end(); ++it )
2775  {
2776  QColor result = parseColor( *it, true );
2777  if ( result.isValid() )
2778  {
2779  colors << result;
2780  }
2781  }
2782  if ( colors.length() > 0 )
2783  {
2784  return colors;
2785  }
2786 
2787  //try splitting string just at newlines
2788  components = colorStr.split( QString( "\n" ) );
2789  it = components.begin();
2790  for ( ; it != components.end(); ++it )
2791  {
2792  QColor result = parseColor( *it, true );
2793  if ( result.isValid() )
2794  {
2795  colors << result;
2796  }
2797  }
2798 
2799  return colors;
2800 }
2801 
2803 {
2804  QgsNamedColorList mimeColors;
2805 
2806  //prefer xml format
2807  if ( data->hasFormat( "text/xml" ) )
2808  {
2809  //get XML doc
2810  QByteArray encodedData = data->data( "text/xml" );
2811  QDomDocument xmlDoc;
2812  xmlDoc.setContent( encodedData );
2813 
2814  QDomElement dragDataElem = xmlDoc.documentElement();
2815  if ( dragDataElem.tagName() == "ColorSchemeModelDragData" )
2816  {
2817  QDomNodeList nodeList = dragDataElem.childNodes();
2818  int nChildNodes = nodeList.size();
2819  QDomElement currentElem;
2820 
2821  for ( int i = 0; i < nChildNodes; ++i )
2822  {
2823  currentElem = nodeList.at( i ).toElement();
2824  if ( currentElem.isNull() )
2825  {
2826  continue;
2827  }
2828 
2829  QPair< QColor, QString> namedColor;
2830  namedColor.first = QgsSymbolLayerV2Utils::decodeColor( currentElem.attribute( "color", "255,255,255,255" ) );
2831  namedColor.second = currentElem.attribute( "label", "" );
2832 
2833  mimeColors << namedColor;
2834  }
2835  }
2836  }
2837 
2838  if ( mimeColors.length() == 0 && data->hasFormat( "application/x-colorobject-list" ) )
2839  {
2840  //get XML doc
2841  QByteArray encodedData = data->data( "application/x-colorobject-list" );
2842  QDomDocument xmlDoc;
2843  xmlDoc.setContent( encodedData );
2844 
2845  QDomNodeList colorsNodes = xmlDoc.elementsByTagName( QString( "colors" ) );
2846  if ( colorsNodes.length() > 0 )
2847  {
2848  QDomElement colorsElem = colorsNodes.at( 0 ).toElement();
2849  QDomNodeList colorNodeList = colorsElem.childNodes();
2850  int nChildNodes = colorNodeList.size();
2851  QDomElement currentElem;
2852 
2853  for ( int i = 0; i < nChildNodes; ++i )
2854  {
2855  //li element
2856  currentElem = colorNodeList.at( i ).toElement();
2857  if ( currentElem.isNull() )
2858  {
2859  continue;
2860  }
2861 
2862  QDomNodeList colorNodes = currentElem.elementsByTagName( QString( "color" ) );
2863  QDomNodeList nameNodes = currentElem.elementsByTagName( QString( "name" ) );
2864 
2865  if ( colorNodes.length() > 0 )
2866  {
2867  QDomElement colorElem = colorNodes.at( 0 ).toElement();
2868 
2869  QStringList colorParts = colorElem.text().simplified().split( " " );
2870  if ( colorParts.length() < 3 )
2871  {
2872  continue;
2873  }
2874 
2875  int red = colorParts.at( 0 ).toDouble() * 255;
2876  int green = colorParts.at( 1 ).toDouble() * 255;
2877  int blue = colorParts.at( 2 ).toDouble() * 255;
2878  QPair< QColor, QString> namedColor;
2879  namedColor.first = QColor( red, green, blue );
2880  if ( nameNodes.length() > 0 )
2881  {
2882  QDomElement nameElem = nameNodes.at( 0 ).toElement();
2883  namedColor.second = nameElem.text();
2884  }
2885  mimeColors << namedColor;
2886  }
2887  }
2888  }
2889  }
2890 
2891  if ( mimeColors.length() == 0 && data->hasText() )
2892  {
2893  //attempt to read color data from mime text
2894  QList< QColor > parsedColors = QgsSymbolLayerV2Utils::parseColorList( data->text() );
2895  QList< QColor >::iterator it = parsedColors.begin();
2896  for ( ; it != parsedColors.end(); ++it )
2897  {
2898  mimeColors << qMakePair( *it, QString() );
2899  }
2900  }
2901 
2902  if ( mimeColors.length() == 0 && data->hasColor() )
2903  {
2904  //attempt to read color data directly from mime
2905  QColor mimeColor = data->colorData().value<QColor>();
2906  if ( mimeColor.isValid() )
2907  {
2908  mimeColors << qMakePair( mimeColor, QString() );
2909  }
2910  }
2911 
2912  return mimeColors;
2913 }
2914 
2915 QMimeData* QgsSymbolLayerV2Utils::colorListToMimeData( const QgsNamedColorList colorList, const bool allFormats )
2916 {
2917  //native format
2918  QMimeData* mimeData = new QMimeData();
2919  QDomDocument xmlDoc;
2920  QDomElement xmlRootElement = xmlDoc.createElement( "ColorSchemeModelDragData" );
2921  xmlDoc.appendChild( xmlRootElement );
2922 
2923  QgsNamedColorList::const_iterator colorIt = colorList.constBegin();
2924  for ( ; colorIt != colorList.constEnd(); ++colorIt )
2925  {
2926  QDomElement namedColor = xmlDoc.createElement( "NamedColor" );
2927  namedColor.setAttribute( "color", QgsSymbolLayerV2Utils::encodeColor(( *colorIt ).first ) );
2928  namedColor.setAttribute( "label", ( *colorIt ).second );
2929  xmlRootElement.appendChild( namedColor );
2930  }
2931  mimeData->setData( "text/xml", xmlDoc.toByteArray() );
2932 
2933  if ( !allFormats )
2934  {
2935  return mimeData;
2936  }
2937 
2938  //set mime text to list of hex values
2939  colorIt = colorList.constBegin();
2940  QStringList colorListString;
2941  for ( ; colorIt != colorList.constEnd(); ++colorIt )
2942  {
2943  colorListString << ( *colorIt ).first.name();
2944  }
2945  mimeData->setText( colorListString.join( "\n" ) );
2946 
2947  //set mime color data to first color
2948  if ( colorList.length() > 0 )
2949  {
2950  mimeData->setColorData( QVariant( colorList.at( 0 ).first ) );
2951  }
2952 
2953  return mimeData;
2954 }
2955 
2956 bool QgsSymbolLayerV2Utils::saveColorsToGpl( QFile &file, const QString paletteName, QgsNamedColorList colors )
2957 {
2958  if ( !file.open( QIODevice::ReadWrite ) )
2959  {
2960  return false;
2961  }
2962 
2963  QTextStream stream( &file );
2964  stream << "GIMP Palette" << endl;
2965  if ( paletteName.isEmpty() )
2966  {
2967  stream << "Name: QGIS Palette" << endl;
2968  }
2969  else
2970  {
2971  stream << "Name: " << paletteName << endl;
2972  }
2973  stream << "Columns: 4" << endl;
2974  stream << "#" << endl;
2975 
2976  for ( QgsNamedColorList::ConstIterator colorIt = colors.constBegin(); colorIt != colors.constEnd(); ++colorIt )
2977  {
2978  QColor color = ( *colorIt ).first;
2979  if ( !color.isValid() )
2980  {
2981  continue;
2982  }
2983  stream << QString( "%1 %2 %3" ).arg( color.red(), 3 ).arg( color.green(), 3 ).arg( color.blue(), 3 );
2984  stream << "\t" << (( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << endl;
2985  }
2986  file.close();
2987 
2988  return true;
2989 }
2990 
2992 {
2993  QgsNamedColorList importedColors;
2994 
2995  if ( !file.open( QIODevice::ReadOnly ) )
2996  {
2997  ok = false;
2998  return importedColors;
2999  }
3000 
3001  QTextStream in( &file );
3002 
3003  QString line = in.readLine();
3004  if ( !line.startsWith( "GIMP Palette" ) )
3005  {
3006  ok = false;
3007  return importedColors;
3008  }
3009 
3010  //ignore lines until after "#"
3011  while ( !in.atEnd() && !line.startsWith( "#" ) )
3012  {
3013  line = in.readLine();
3014  }
3015  if ( in.atEnd() )
3016  {
3017  ok = false;
3018  return importedColors;
3019  }
3020 
3021  //ready to start reading colors
3022  while ( !in.atEnd() )
3023  {
3024  line = in.readLine();
3025  QStringList parts = line.simplified().split( " " );
3026  if ( parts.length() < 3 )
3027  {
3028  continue;
3029  }
3030  int red = parts.at( 0 ).toInt();
3031  int green = parts.at( 1 ).toInt();
3032  int blue = parts.at( 2 ).toInt();
3033  QColor color = QColor( red, green, blue );
3034 
3035  //try to read color name
3036  QString label;
3037  parts = line.split( "\t" );
3038  if ( parts.length() > 1 )
3039  {
3040  label = parts.at( parts.length() - 1 );
3041  }
3042 
3043  importedColors << qMakePair( color, label );
3044  }
3045 
3046  file.close();
3047  ok = true;
3048  return importedColors;
3049 }
3050 
3051 QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr , bool strictEval )
3052 {
3053  bool hasAlpha;
3054  return parseColorWithAlpha( colorStr, hasAlpha, strictEval );
3055 }
3056 
3057 QColor QgsSymbolLayerV2Utils::parseColorWithAlpha( const QString colorStr, bool &containsAlpha, bool strictEval )
3058 {
3059  QColor parsedColor;
3060 
3061  //color in hex format "#aabbcc"
3062  if ( QColor::isValidColor( colorStr ) )
3063  {
3064  //string is a valid hex color string
3065  parsedColor.setNamedColor( colorStr );
3066  if ( parsedColor.isValid() )
3067  {
3068  containsAlpha = false;
3069  return parsedColor;
3070  }
3071  }
3072 
3073  if ( !strictEval )
3074  {
3075  //color in hex format, without #
3076  QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
3077  if ( hexColorRx2.indexIn( colorStr ) != -1 )
3078  {
3079  //add "#" and parse
3080  parsedColor.setNamedColor( QString( "#" ) + colorStr );
3081  if ( parsedColor.isValid() )
3082  {
3083  containsAlpha = false;
3084  return parsedColor;
3085  }
3086  }
3087  }
3088 
3089  //color in (rrr,ggg,bbb) format, brackets and rgb prefix optional
3090  QRegExp rgbFormatRx( "^\\s*(?:rgb)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*\\)?\\s*;?\\s*$" );
3091  if ( rgbFormatRx.indexIn( colorStr ) != -1 )
3092  {
3093  int r = rgbFormatRx.cap( 1 ).toInt();
3094  int g = rgbFormatRx.cap( 2 ).toInt();
3095  int b = rgbFormatRx.cap( 3 ).toInt();
3096  parsedColor.setRgb( r, g, b );
3097  if ( parsedColor.isValid() )
3098  {
3099  containsAlpha = false;
3100  return parsedColor;
3101  }
3102  }
3103 
3104  //color in (r%,g%,b%) format, brackets and rgb prefix optional
3105  QRegExp rgbPercentFormatRx( "^\\s*(?:rgb)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*\\)?\\s*;?\\s*$" );
3106  if ( rgbPercentFormatRx.indexIn( colorStr ) != -1 )
3107  {
3108  int r = qRound( rgbPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
3109  int g = qRound( rgbPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
3110  int b = qRound( rgbPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
3111  parsedColor.setRgb( r, g, b );
3112  if ( parsedColor.isValid() )
3113  {
3114  containsAlpha = false;
3115  return parsedColor;
3116  }
3117  }
3118 
3119  //color in (r,g,b,a) format, brackets and rgba prefix optional
3120  QRegExp rgbaFormatRx( "^\\s*(?:rgba)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
3121  if ( rgbaFormatRx.indexIn( colorStr ) != -1 )
3122  {
3123  int r = rgbaFormatRx.cap( 1 ).toInt();
3124  int g = rgbaFormatRx.cap( 2 ).toInt();
3125  int b = rgbaFormatRx.cap( 3 ).toInt();
3126  int a = qRound( rgbaFormatRx.cap( 4 ).toDouble() * 255.0 );
3127  parsedColor.setRgb( r, g, b, a );
3128  if ( parsedColor.isValid() )
3129  {
3130  containsAlpha = true;
3131  return parsedColor;
3132  }
3133  }
3134 
3135  //color in (r%,g%,b%,a) format, brackets and rgba prefix optional
3136  QRegExp rgbaPercentFormatRx( "^\\s*(?:rgba)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
3137  if ( rgbaPercentFormatRx.indexIn( colorStr ) != -1 )
3138  {
3139  int r = qRound( rgbaPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
3140  int g = qRound( rgbaPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
3141  int b = qRound( rgbaPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
3142  int a = qRound( rgbaPercentFormatRx.cap( 4 ).toDouble() * 255.0 );
3143  parsedColor.setRgb( r, g, b, a );
3144  if ( parsedColor.isValid() )
3145  {
3146  containsAlpha = true;
3147  return parsedColor;
3148  }
3149  }
3150 
3151  //couldn't parse string as color
3152  return QColor();
3153 }
3154 
3156 {
3157 
3158  if ( u == QgsSymbolV2::MM )
3159  {
3160  return c.scaleFactor();
3161  }
3162  else //QgsSymbol::MapUnit
3163  {
3164  double mup = scale.computeMapUnitsPerPixel( c );
3165  if ( mup > 0 )
3166  {
3167  return 1.0 / mup;
3168  }
3169  else
3170  {
3171  return 1.0;
3172  }
3173  }
3174 }
3175 
3177 {
3178  if ( u == QgsSymbolV2::MM )
3179  {
3180  return ( c.scaleFactor() * c.rasterScaleFactor() );
3181  }
3182  else //QgsSymbol::MapUnit
3183  {
3184  double mup = scale.computeMapUnitsPerPixel( c );
3185  if ( mup > 0 )
3186  {
3187  return c.rasterScaleFactor() / mup;
3188  }
3189  else
3190  {
3191  return 1.0;
3192  }
3193  }
3194 }
3195 
3197 {
3198  QgsRenderContext context;
3199  context.setPainter( p );
3200  context.setRasterScaleFactor( 1.0 );
3201  if ( p && p->device() )
3202  {
3203  context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
3204  }
3205  else
3206  {
3207  context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
3208  }
3209  return context;
3210 }
3211 
3212 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
3213 {
3214  if ( !image )
3215  {
3216  return;
3217  }
3218 
3219  QRgb myRgb;
3220  QImage::Format format = image->format();
3221  if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
3222  {
3223  QgsDebugMsg( "no alpha channel." );
3224  return;
3225  }
3226 
3227  //change the alpha component of every pixel
3228  for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
3229  {
3230  QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
3231  for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
3232  {
3233  myRgb = scanLine[widthIndex];
3234  if ( format == QImage::Format_ARGB32_Premultiplied )
3235  scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
3236  else
3237  scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
3238  }
3239  }
3240 }
3241 
3242 void QgsSymbolLayerV2Utils::blurImageInPlace( QImage& image, const QRect& rect, int radius, bool alphaOnly )
3243 {
3244  // culled from Qt's qpixmapfilter.cpp, see: http://www.qtcentre.org/archive/index.php/t-26534.html
3245  int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
3246  int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius-1];
3247 
3248  if ( image.format() != QImage::Format_ARGB32_Premultiplied
3249  && image.format() != QImage::Format_RGB32 )
3250  {
3251  image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
3252  }
3253 
3254  int r1 = rect.top();
3255  int r2 = rect.bottom();
3256  int c1 = rect.left();
3257  int c2 = rect.right();
3258 
3259  int bpl = image.bytesPerLine();
3260  int rgba[4];
3261  unsigned char* p;
3262 
3263  int i1 = 0;
3264  int i2 = 3;
3265 
3266  if ( alphaOnly ) // this seems to only work right for a black color
3267  i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
3268 
3269  for ( int col = c1; col <= c2; col++ )
3270  {
3271  p = image.scanLine( r1 ) + col * 4;
3272  for ( int i = i1; i <= i2; i++ )
3273  rgba[i] = p[i] << 4;
3274 
3275  p += bpl;
3276  for ( int j = r1; j < r2; j++, p += bpl )
3277  for ( int i = i1; i <= i2; i++ )
3278  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3279  }
3280 
3281  for ( int row = r1; row <= r2; row++ )
3282  {
3283  p = image.scanLine( row ) + c1 * 4;
3284  for ( int i = i1; i <= i2; i++ )
3285  rgba[i] = p[i] << 4;
3286 
3287  p += 4;
3288  for ( int j = c1; j < c2; j++, p += 4 )
3289  for ( int i = i1; i <= i2; i++ )
3290  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3291  }
3292 
3293  for ( int col = c1; col <= c2; col++ )
3294  {
3295  p = image.scanLine( r2 ) + col * 4;
3296  for ( int i = i1; i <= i2; i++ )
3297  rgba[i] = p[i] << 4;
3298 
3299  p -= bpl;
3300  for ( int j = r1; j < r2; j++, p -= bpl )
3301  for ( int i = i1; i <= i2; i++ )
3302  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3303  }
3304 
3305  for ( int row = r1; row <= r2; row++ )
3306  {
3307  p = image.scanLine( row ) + c2 * 4;
3308  for ( int i = i1; i <= i2; i++ )
3309  rgba[i] = p[i] << 4;
3310 
3311  p -= 4;
3312  for ( int j = c1; j < c2; j++, p -= 4 )
3313  for ( int i = i1; i <= i2; i++ )
3314  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3315  }
3316 }
3317 
3318 void QgsSymbolLayerV2Utils::premultiplyColor( QColor &rgb, int alpha )
3319 {
3320  int r = 0, g = 0, b = 0;
3321  double alphaFactor = 1.0;
3322 
3323  if ( alpha != 255 && alpha > 0 )
3324  {
3325  // Semi-transparent pixel. We need to adjust the colors for ARGB32_Premultiplied images
3326  // where color values have to be premultiplied by alpha
3327 
3328  rgb.getRgb( &r, &g, &b );
3329 
3330  alphaFactor = alpha / 255.;
3331  r *= alphaFactor;
3332  g *= alphaFactor;
3333  b *= alphaFactor;
3334  rgb.setRgb( r, g, b, alpha );
3335  }
3336  else if ( alpha == 0 )
3337  {
3338  rgb.setRgb( 0, 0, 0, 0 );
3339  }
3340 }
3341 
3342 #if 0
3343 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
3344 {
3345  switch ( lhs.type() )
3346  {
3347  case QVariant::Int:
3348  return lhs.toInt() < rhs.toInt();
3349  case QVariant::UInt:
3350  return lhs.toUInt() < rhs.toUInt();
3351  case QVariant::LongLong:
3352  return lhs.toLongLong() < rhs.toLongLong();
3353  case QVariant::ULongLong:
3354  return lhs.toULongLong() < rhs.toULongLong();
3355  case QVariant::Double:
3356  return lhs.toDouble() < rhs.toDouble();
3357  case QVariant::Char:
3358  return lhs.toChar() < rhs.toChar();
3359  case QVariant::Date:
3360  return lhs.toDate() < rhs.toDate();
3361  case QVariant::Time:
3362  return lhs.toTime() < rhs.toTime();
3363  case QVariant::DateTime:
3364  return lhs.toDateTime() < rhs.toDateTime();
3365  default:
3366  return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
3367  }
3368 }
3369 
3370 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
3371 {
3372  return ! _QVariantLessThan( lhs, rhs );
3373 }
3374 #endif
3375 
3376 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
3377 {
3378  if ( order == Qt::AscendingOrder )
3379  {
3380  //qSort( list.begin(), list.end(), _QVariantLessThan );
3381  qSort( list.begin(), list.end(), qgsVariantLessThan );
3382  }
3383  else // Qt::DescendingOrder
3384  {
3385  //qSort( list.begin(), list.end(), _QVariantGreaterThan );
3386  qSort( list.begin(), list.end(), qgsVariantGreaterThan );
3387  }
3388 }
3389 
3390 QPointF QgsSymbolLayerV2Utils::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance )
3391 {
3392  double dx = directionPoint.x() - startPoint.x();
3393  double dy = directionPoint.y() - startPoint.y();
3394  double length = sqrt( dx * dx + dy * dy );
3395  double scaleFactor = distance / length;
3396  return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
3397 }
3398 
3399 
3401 {
3402  // copied from QgsMarkerCatalogue - TODO: unify
3403  QStringList list;
3404  QStringList svgPaths = QgsApplication::svgPaths();
3405 
3406  for ( int i = 0; i < svgPaths.size(); i++ )
3407  {
3408  QDir dir( svgPaths[i] );
3409  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
3410  {
3411  svgPaths.insert( i + 1, dir.path() + "/" + item );
3412  }
3413 
3414  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
3415  {
3416  // TODO test if it is correct SVG
3417  list.append( dir.path() + "/" + item );
3418  }
3419  }
3420  return list;
3421 }
3422 
3423 // Stripped down version of listSvgFiles() for specified directory
3424 QStringList QgsSymbolLayerV2Utils::listSvgFilesAt( QString directory )
3425 {
3426  // TODO anything that applies for the listSvgFiles() applies this also
3427 
3428  QStringList list;
3429  QStringList svgPaths;
3430  svgPaths.append( directory );
3431 
3432  for ( int i = 0; i < svgPaths.size(); i++ )
3433  {
3434  QDir dir( svgPaths[i] );
3435  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
3436  {
3437  svgPaths.insert( i + 1, dir.path() + "/" + item );
3438  }
3439 
3440  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
3441  {
3442  list.append( dir.path() + "/" + item );
3443  }
3444  }
3445  return list;
3446 
3447 }
3448 
3450 {
3451  // copied from QgsSymbol::setNamedPointSymbol - TODO: unify
3452 
3453  // we might have a full path...
3454  if ( QFile( name ).exists() )
3455  return QFileInfo( name ).canonicalFilePath();
3456 
3457  // or it might be an url...
3458  if ( name.contains( "://" ) )
3459  {
3460  QUrl url( name );
3461  if ( url.isValid() && !url.scheme().isEmpty() )
3462  {
3463  if ( url.scheme().compare( "file", Qt::CaseInsensitive ) == 0 )
3464  {
3465  // it's a url to a local file
3466  name = url.toLocalFile();
3467  if ( QFile( name ).exists() )
3468  {
3469  return QFileInfo( name ).canonicalFilePath();
3470  }
3471  }
3472  else
3473  {
3474  // it's a url pointing to a online resource
3475  return name;
3476  }
3477  }
3478  }
3479 
3480  // SVG symbol not found - probably a relative path was used
3481 
3482  QStringList svgPaths = QgsApplication::svgPaths();
3483  for ( int i = 0; i < svgPaths.size(); i++ )
3484  {
3485  QString svgPath = svgPaths[i];
3486  if ( svgPath.endsWith( QString( "/" ) ) )
3487  {
3488  svgPath.chop( 1 );
3489  }
3490 
3491  QgsDebugMsg( "SvgPath: " + svgPath );
3492  // Not sure why to lowest dir was used instead of full relative path, it was causing #8664
3493  //QFileInfo myInfo( name );
3494  //QString myFileName = myInfo.fileName(); // foo.svg
3495  //QString myLowestDir = myInfo.dir().dirName();
3496  //QString myLocalPath = svgPath + QString( myLowestDir.isEmpty() ? "" : "/" + myLowestDir ) + "/" + myFileName;
3497  QString myLocalPath = svgPath + QDir::separator() + name;
3498 
3499  QgsDebugMsg( "Alternative svg path: " + myLocalPath );
3500  if ( QFile( myLocalPath ).exists() )
3501  {
3502  QgsDebugMsg( "Svg found in alternative path" );
3503  return QFileInfo( myLocalPath ).canonicalFilePath();
3504  }
3505  }
3506 
3507  QFileInfo pfi( QgsProject::instance()->fileName() );
3508  QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
3509  if ( pfi.exists() && QFile( alternatePath ).exists() )
3510  {
3511  QgsDebugMsg( "Svg found in alternative path" );
3512  return QFileInfo( alternatePath ).canonicalFilePath();
3513  }
3514  else
3515  {
3516  QgsDebugMsg( "Svg not found in project path" );
3517  }
3518  //couldnt find the file, no happy ending :-(
3519  QgsDebugMsg( "Computed alternate path but no svg there either" );
3520 
3521  return QString();
3522 }
3523 
3525 {
3526  // copied from QgsSymbol::writeXML
3527 
3528  QFileInfo fi( path );
3529  if ( !fi.exists() )
3530  return path;
3531 
3532  path = fi.canonicalFilePath();
3533 
3534  QStringList svgPaths = QgsApplication::svgPaths();
3535 
3536  bool isInSvgPathes = false;
3537  for ( int i = 0; i < svgPaths.size(); i++ )
3538  {
3539  QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
3540 
3541  if ( !dir.isEmpty() && path.startsWith( dir ) )
3542  {
3543  path = path.mid( dir.size() + 1 );
3544  isInSvgPathes = true;
3545  break;
3546  }
3547  }
3548 
3549  if ( isInSvgPathes )
3550  return path;
3551 
3552  return QgsProject::instance()->writePath( path );
3553 }
3554 
3555 QPointF QgsSymbolLayerV2Utils::polygonCentroid( const QPolygonF& points )
3556 {
3557  //Calculate the centroid of points
3558  double cx = 0, cy = 0;
3559  double area, sum = 0;
3560  for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
3561  {
3562  const QPointF& p1 = points[i];
3563  const QPointF& p2 = points[j];
3564  area = p1.x() * p2.y() - p1.y() * p2.x();
3565  sum += area;
3566  cx += ( p1.x() + p2.x() ) * area;
3567  cy += ( p1.y() + p2.y() ) * area;
3568  }
3569  sum *= 3.0;
3570  cx /= sum;
3571  cy /= sum;
3572 
3573  return QPointF( cx, cy );
3574 }
3575 
3576 QPointF QgsSymbolLayerV2Utils::polygonPointOnSurface( const QPolygonF& points )
3577 {
3578  QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
3579 
3580  // check if centroid inside in polygon
3581  if ( !QgsSymbolLayerV2Utils::pointInPolygon( points, centroid ) )
3582  {
3583  unsigned int i, pointCount = points.count();
3584 
3585  QgsPolyline polyline( pointCount );
3586  for ( i = 0; i < pointCount; ++i ) polyline[i] = QgsPoint( points[i].x(), points[i].y() );
3587 
3588  QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << polyline );
3589  if ( geom )
3590  {
3591  QgsGeometry* pointOnSurfaceGeom = geom->pointOnSurface();
3592 
3593  if ( pointOnSurfaceGeom )
3594  {
3595  QgsPoint point = pointOnSurfaceGeom->asPoint();
3596  delete pointOnSurfaceGeom;
3597  delete geom;
3598 
3599  return QPointF( point.x(), point.y() );
3600  }
3601  delete geom;
3602  }
3603  }
3604  return centroid;
3605 }
3606 
3607 bool QgsSymbolLayerV2Utils::pointInPolygon( const QPolygonF &points, const QPointF &point )
3608 {
3609  bool inside = false;
3610 
3611  double x = point.x();
3612  double y = point.y();
3613 
3614  for ( int i = 0, j = points.count() - 1; i < points.count(); i++ )
3615  {
3616  const QPointF& p1 = points[i];
3617  const QPointF& p2 = points[j];
3618 
3619  if ( p1.x() == x && p1.y() == y )
3620  return true;
3621 
3622  if (( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
3623  {
3624  if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() )*( p2.x() - p1.x() ) <= x )
3625  inside = !inside;
3626  }
3627 
3628  j = i;
3629  }
3630  return inside;
3631 }
3632 
3634 {
3635  if ( fieldOrExpression.isEmpty() )
3636  return 0;
3637 
3638  QgsExpression* expr = new QgsExpression( fieldOrExpression );
3639  if ( !expr->hasParserError() )
3640  return expr;
3641 
3642  // now try with quoted field name
3643  delete expr;
3644  QgsExpression* expr2 = new QgsExpression( QgsExpression::quotedColumnRef( fieldOrExpression ) );
3645  Q_ASSERT( !expr2->hasParserError() );
3646  return expr2;
3647 }
3648 
3650 {
3651  const QgsExpression::Node* n = expression->rootNode();
3652 
3653  if ( n && n->nodeType() == QgsExpression::ntColumnRef )
3654  return static_cast<const QgsExpression::NodeColumnRef*>( n )->name();
3655 
3656  return expression->expression();
3657 }
3658 
3659 
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 QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok)
Imports colors from a gpl GIMP palette file.
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 QIcon symbolLayerPreviewIcon(QgsSymbolLayerV2 *layer, QgsSymbolV2::OutputUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
static QPixmap colorRampPreviewPixmap(QgsVectorColorRampV2 *ramp, QSize size)
GeometryType
Definition: qgis.h:155
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
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
Alias for dump()
SymbolType type() const
Definition: qgssymbolv2.h:79
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
static QString encodeSldUom(QgsSymbolV2::OutputUnit unit, double *scaleFactor)
QgsMultiPolyline asMultiPolyline() const
return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list
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)
double computeMapUnitsPerPixel(const QgsRenderContext &c) const
QgsPolygon asPolygon() const
return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list ...
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)
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
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)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
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 maxScale
The maximum scale, or 0.0 if unset.
double x() const
Definition: qgspoint.h:110
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:210
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsMultiPolygon asMultiPolygon() const
return contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty ...
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
static QString encodeColor(QColor color)
QgsGeometry * offsetCurve(double distance, int segments, int joinStyle, double mitreLimit)
Returns an offset line at a given distance and side from an input line.
static Qt::BrushStyle decodeSldBrushStyle(QString str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
static WkbType flatType(WkbType type)
Definition: qgis.h:99
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 QPainter::CompositionMode decodeBlendMode(const QString &s)
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 QColor parseColorWithAlpha(const QString colorStr, bool &containsAlpha, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes...
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
void setScaleFactor(double factor)
QgsGeometry * buffer(double distance, int segments)
Returns a buffer region around this geometry having the given width and with a specified number of se...
static QgsSymbolLayerV2 * createFillLayerFromSld(QDomElement &element)
static QString encodePoint(QPointF point)
static QMimeData * colorListToMimeData(const QgsNamedColorList colorList, const bool allFormats=true)
Creates mime data from a list of named colors.
static bool saveColorsToGpl(QFile &file, const QString paletteName, QgsNamedColorList colors)
Exports colors to a gpl GIMP palette file.
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:128
static Qt::PenCapStyle decodePenCapStyle(QString str)
static Qt::PenStyle decodePenStyle(QString str)
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)
QVector< QgsPolygon > QgsMultiPolygon
a collection of QgsPolygons that share a common collection of attributes
Definition: qgsgeometry.h:53
static QFont::Style decodeSldFontStyle(QString str)
static QgsSymbolV2::OutputUnit decodeSldUom(QString str, double *scaleFactor)
int symbolLayerCount()
Definition: qgssymbolv2.h:85
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
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
static Qt::PenJoinStyle decodeSldLineJoinStyle(QString str)
QVector< QgsPolyline > QgsPolygon
polygon: first item of the list is outer ring, inner rings (if any) start from second item ...
Definition: qgsgeometry.h:44
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)
QgsGeometry * pointOnSurface()
Returns a point within a geometry.
static bool geometryFromSldElement(QDomElement &element, QString &geomFunc)
static QgsSymbolLayerV2 * loadSymbolLayer(QDomElement &element)
static bool pointInPolygon(const QPolygonF &points, const QPointF &point)
Calculate whether a point is within of a QPolygonF.
static QgsSymbolLayerV2 * createLineLayerFromSld(QDomElement &element)
static QString encodeRealVector(const QVector< qreal > &v)
int renderingPass() const
virtual QString layerType() const =0
QVector< QgsPolyline > QgsMultiPolyline
a collection of QgsPolylines that share a common collection of attributes
Definition: qgsgeometry.h:50
QString file
Definition: qgssvgcache.cpp:76
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 double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
static 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< QPolygonF > offsetLine(QPolygonF polyline, double dist, QGis::GeometryType geometryType)
calculate geometry shifted by a specified distance
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:39
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 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)
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 QList< QColor > parseColorList(const QString colorStr)
Attempts to parse a string as a list of colors using a variety of common formats, including hex codes...
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 QgsGeometry * fromPolygon(const QgsPolygon &polygon)
construct geometry from a polygon
static void drawStippledBackround(QPainter *painter, QRect rect)
static bool onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
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 polygonPointOnSurface(const QPolygonF &points)
Calculate a point within of a QPolygonF.
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=0)
Draw icon of the symbol that occupyies area given by size using the painter.
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [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 minScale
The minimum scale, or 0.0 if unset.
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)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:130
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 QColor parseColor(QString colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes...
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
static bool needEllipseMarker(QDomElement &element)
static QString encodePenCapStyle(Qt::PenCapStyle style)