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 QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr )
2736 {
2737  bool hasAlpha;
2738  return parseColorWithAlpha( colorStr, hasAlpha );
2739 }
2740 
2741 QColor QgsSymbolLayerV2Utils::parseColorWithAlpha( const QString colorStr, bool &containsAlpha )
2742 {
2743  QColor parsedColor;
2744 
2745  //color in hex format "#aabbcc"
2746  if ( QColor::isValidColor( colorStr ) )
2747  {
2748  //string is a valid hex color string
2749  parsedColor.setNamedColor( colorStr );
2750  if ( parsedColor.isValid() )
2751  {
2752  containsAlpha = false;
2753  return parsedColor;
2754  }
2755  }
2756 
2757  //color in hex format, without #
2758  QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
2759  if ( hexColorRx2.indexIn( colorStr ) != -1 )
2760  {
2761  //add "#" and parse
2762  parsedColor.setNamedColor( QString( "#" ) + colorStr );
2763  if ( parsedColor.isValid() )
2764  {
2765  containsAlpha = false;
2766  return parsedColor;
2767  }
2768  }
2769 
2770  //color in (rrr,ggg,bbb) format, brackets and rgb prefix optional
2771  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*$" );
2772  if ( rgbFormatRx.indexIn( colorStr ) != -1 )
2773  {
2774  int r = rgbFormatRx.cap( 1 ).toInt();
2775  int g = rgbFormatRx.cap( 2 ).toInt();
2776  int b = rgbFormatRx.cap( 3 ).toInt();
2777  parsedColor.setRgb( r, g, b );
2778  if ( parsedColor.isValid() )
2779  {
2780  containsAlpha = false;
2781  return parsedColor;
2782  }
2783  }
2784 
2785  //color in (r%,g%,b%) format, brackets and rgb prefix optional
2786  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*$" );
2787  if ( rgbPercentFormatRx.indexIn( colorStr ) != -1 )
2788  {
2789  int r = qRound( rgbPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
2790  int g = qRound( rgbPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
2791  int b = qRound( rgbPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
2792  parsedColor.setRgb( r, g, b );
2793  if ( parsedColor.isValid() )
2794  {
2795  containsAlpha = false;
2796  return parsedColor;
2797  }
2798  }
2799 
2800  //color in (r,g,b,a) format, brackets and rgba prefix optional
2801  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*$" );
2802  if ( rgbaFormatRx.indexIn( colorStr ) != -1 )
2803  {
2804  int r = rgbaFormatRx.cap( 1 ).toInt();
2805  int g = rgbaFormatRx.cap( 2 ).toInt();
2806  int b = rgbaFormatRx.cap( 3 ).toInt();
2807  int a = qRound( rgbaFormatRx.cap( 4 ).toDouble() * 255.0 );
2808  parsedColor.setRgb( r, g, b, a );
2809  if ( parsedColor.isValid() )
2810  {
2811  containsAlpha = true;
2812  return parsedColor;
2813  }
2814  }
2815 
2816  //color in (r%,g%,b%,a) format, brackets and rgba prefix optional
2817  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*$" );
2818  if ( rgbaPercentFormatRx.indexIn( colorStr ) != -1 )
2819  {
2820  int r = qRound( rgbaPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
2821  int g = qRound( rgbaPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
2822  int b = qRound( rgbaPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
2823  int a = qRound( rgbaPercentFormatRx.cap( 4 ).toDouble() * 255.0 );
2824  parsedColor.setRgb( r, g, b, a );
2825  if ( parsedColor.isValid() )
2826  {
2827  containsAlpha = true;
2828  return parsedColor;
2829  }
2830  }
2831 
2832  //couldn't parse string as color
2833  return QColor();
2834 }
2835 
2837 {
2838 
2839  if ( u == QgsSymbolV2::MM )
2840  {
2841  return c.scaleFactor();
2842  }
2843  else //QgsSymbol::MapUnit
2844  {
2845  double mup = scale.computeMapUnitsPerPixel( c );
2846  if ( mup > 0 )
2847  {
2848  return 1.0 / mup;
2849  }
2850  else
2851  {
2852  return 1.0;
2853  }
2854  }
2855 }
2856 
2858 {
2859  if ( u == QgsSymbolV2::MM )
2860  {
2861  return ( c.scaleFactor() * c.rasterScaleFactor() );
2862  }
2863  else //QgsSymbol::MapUnit
2864  {
2865  double mup = scale.computeMapUnitsPerPixel( c );
2866  if ( mup > 0 )
2867  {
2868  return c.rasterScaleFactor() / mup;
2869  }
2870  else
2871  {
2872  return 1.0;
2873  }
2874  }
2875 }
2876 
2878 {
2879  QgsRenderContext context;
2880  context.setPainter( p );
2881  context.setRasterScaleFactor( 1.0 );
2882  if ( p && p->device() )
2883  {
2884  context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
2885  }
2886  else
2887  {
2888  context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
2889  }
2890  return context;
2891 }
2892 
2893 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
2894 {
2895  if ( !image )
2896  {
2897  return;
2898  }
2899 
2900  QRgb myRgb;
2901  QImage::Format format = image->format();
2902  if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
2903  {
2904  QgsDebugMsg( "no alpha channel." );
2905  return;
2906  }
2907 
2908  //change the alpha component of every pixel
2909  for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
2910  {
2911  QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
2912  for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
2913  {
2914  myRgb = scanLine[widthIndex];
2915  if ( format == QImage::Format_ARGB32_Premultiplied )
2916  scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
2917  else
2918  scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
2919  }
2920  }
2921 }
2922 
2923 void QgsSymbolLayerV2Utils::blurImageInPlace( QImage& image, const QRect& rect, int radius, bool alphaOnly )
2924 {
2925  // culled from Qt's qpixmapfilter.cpp, see: http://www.qtcentre.org/archive/index.php/t-26534.html
2926  int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
2927  int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius-1];
2928 
2929  if ( image.format() != QImage::Format_ARGB32_Premultiplied
2930  && image.format() != QImage::Format_RGB32 )
2931  {
2932  image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
2933  }
2934 
2935  int r1 = rect.top();
2936  int r2 = rect.bottom();
2937  int c1 = rect.left();
2938  int c2 = rect.right();
2939 
2940  int bpl = image.bytesPerLine();
2941  int rgba[4];
2942  unsigned char* p;
2943 
2944  int i1 = 0;
2945  int i2 = 3;
2946 
2947  if ( alphaOnly ) // this seems to only work right for a black color
2948  i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
2949 
2950  for ( int col = c1; col <= c2; col++ )
2951  {
2952  p = image.scanLine( r1 ) + col * 4;
2953  for ( int i = i1; i <= i2; i++ )
2954  rgba[i] = p[i] << 4;
2955 
2956  p += bpl;
2957  for ( int j = r1; j < r2; j++, p += bpl )
2958  for ( int i = i1; i <= i2; i++ )
2959  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2960  }
2961 
2962  for ( int row = r1; row <= r2; row++ )
2963  {
2964  p = image.scanLine( row ) + c1 * 4;
2965  for ( int i = i1; i <= i2; i++ )
2966  rgba[i] = p[i] << 4;
2967 
2968  p += 4;
2969  for ( int j = c1; j < c2; j++, p += 4 )
2970  for ( int i = i1; i <= i2; i++ )
2971  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2972  }
2973 
2974  for ( int col = c1; col <= c2; col++ )
2975  {
2976  p = image.scanLine( r2 ) + col * 4;
2977  for ( int i = i1; i <= i2; i++ )
2978  rgba[i] = p[i] << 4;
2979 
2980  p -= bpl;
2981  for ( int j = r1; j < r2; j++, p -= bpl )
2982  for ( int i = i1; i <= i2; i++ )
2983  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2984  }
2985 
2986  for ( int row = r1; row <= r2; row++ )
2987  {
2988  p = image.scanLine( row ) + c2 * 4;
2989  for ( int i = i1; i <= i2; i++ )
2990  rgba[i] = p[i] << 4;
2991 
2992  p -= 4;
2993  for ( int j = c1; j < c2; j++, p -= 4 )
2994  for ( int i = i1; i <= i2; i++ )
2995  p[i] = ( rgba[i] += (( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
2996  }
2997 }
2998 
2999 void QgsSymbolLayerV2Utils::premultiplyColor( QColor &rgb, int alpha )
3000 {
3001  int r = 0, g = 0, b = 0;
3002  double alphaFactor = 1.0;
3003 
3004  if ( alpha != 255 && alpha > 0 )
3005  {
3006  // Semi-transparent pixel. We need to adjust the colors for ARGB32_Premultiplied images
3007  // where color values have to be premultiplied by alpha
3008 
3009  rgb.getRgb( &r, &g, &b );
3010 
3011  alphaFactor = alpha / 255.;
3012  r *= alphaFactor;
3013  g *= alphaFactor;
3014  b *= alphaFactor;
3015  rgb.setRgb( r, g, b, alpha );
3016  }
3017  else if ( alpha == 0 )
3018  {
3019  rgb.setRgb( 0, 0, 0, 0 );
3020  }
3021 }
3022 
3023 #if 0
3024 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
3025 {
3026  switch ( lhs.type() )
3027  {
3028  case QVariant::Int:
3029  return lhs.toInt() < rhs.toInt();
3030  case QVariant::UInt:
3031  return lhs.toUInt() < rhs.toUInt();
3032  case QVariant::LongLong:
3033  return lhs.toLongLong() < rhs.toLongLong();
3034  case QVariant::ULongLong:
3035  return lhs.toULongLong() < rhs.toULongLong();
3036  case QVariant::Double:
3037  return lhs.toDouble() < rhs.toDouble();
3038  case QVariant::Char:
3039  return lhs.toChar() < rhs.toChar();
3040  case QVariant::Date:
3041  return lhs.toDate() < rhs.toDate();
3042  case QVariant::Time:
3043  return lhs.toTime() < rhs.toTime();
3044  case QVariant::DateTime:
3045  return lhs.toDateTime() < rhs.toDateTime();
3046  default:
3047  return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
3048  }
3049 }
3050 
3051 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
3052 {
3053  return ! _QVariantLessThan( lhs, rhs );
3054 }
3055 #endif
3056 
3057 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
3058 {
3059  if ( order == Qt::AscendingOrder )
3060  {
3061  //qSort( list.begin(), list.end(), _QVariantLessThan );
3062  qSort( list.begin(), list.end(), qgsVariantLessThan );
3063  }
3064  else // Qt::DescendingOrder
3065  {
3066  //qSort( list.begin(), list.end(), _QVariantGreaterThan );
3067  qSort( list.begin(), list.end(), qgsVariantGreaterThan );
3068  }
3069 }
3070 
3071 QPointF QgsSymbolLayerV2Utils::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance )
3072 {
3073  double dx = directionPoint.x() - startPoint.x();
3074  double dy = directionPoint.y() - startPoint.y();
3075  double length = sqrt( dx * dx + dy * dy );
3076  double scaleFactor = distance / length;
3077  return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
3078 }
3079 
3080 
3082 {
3083  // copied from QgsMarkerCatalogue - TODO: unify
3084  QStringList list;
3085  QStringList svgPaths = QgsApplication::svgPaths();
3086 
3087  for ( int i = 0; i < svgPaths.size(); i++ )
3088  {
3089  QDir dir( svgPaths[i] );
3090  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
3091  {
3092  svgPaths.insert( i + 1, dir.path() + "/" + item );
3093  }
3094 
3095  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
3096  {
3097  // TODO test if it is correct SVG
3098  list.append( dir.path() + "/" + item );
3099  }
3100  }
3101  return list;
3102 }
3103 
3104 // Stripped down version of listSvgFiles() for specified directory
3105 QStringList QgsSymbolLayerV2Utils::listSvgFilesAt( QString directory )
3106 {
3107  // TODO anything that applies for the listSvgFiles() applies this also
3108 
3109  QStringList list;
3110  QStringList svgPaths;
3111  svgPaths.append( directory );
3112 
3113  for ( int i = 0; i < svgPaths.size(); i++ )
3114  {
3115  QDir dir( svgPaths[i] );
3116  foreach ( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
3117  {
3118  svgPaths.insert( i + 1, dir.path() + "/" + item );
3119  }
3120 
3121  foreach ( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
3122  {
3123  list.append( dir.path() + "/" + item );
3124  }
3125  }
3126  return list;
3127 
3128 }
3129 
3131 {
3132  // copied from QgsSymbol::setNamedPointSymbol - TODO: unify
3133 
3134  // we might have a full path...
3135  if ( QFile( name ).exists() )
3136  return QFileInfo( name ).canonicalFilePath();
3137 
3138  // or it might be an url...
3139  if ( name.contains( "://" ) )
3140  {
3141  QUrl url( name );
3142  if ( url.isValid() && !url.scheme().isEmpty() )
3143  {
3144  if ( url.scheme().compare( "file", Qt::CaseInsensitive ) == 0 )
3145  {
3146  // it's a url to a local file
3147  name = url.toLocalFile();
3148  if ( QFile( name ).exists() )
3149  {
3150  return QFileInfo( name ).canonicalFilePath();
3151  }
3152  }
3153  else
3154  {
3155  // it's a url pointing to a online resource
3156  return name;
3157  }
3158  }
3159  }
3160 
3161  // SVG symbol not found - probably a relative path was used
3162 
3163  QStringList svgPaths = QgsApplication::svgPaths();
3164  for ( int i = 0; i < svgPaths.size(); i++ )
3165  {
3166  QString svgPath = svgPaths[i];
3167  if ( svgPath.endsWith( QString( "/" ) ) )
3168  {
3169  svgPath.chop( 1 );
3170  }
3171 
3172  QgsDebugMsg( "SvgPath: " + svgPath );
3173  // Not sure why to lowest dir was used instead of full relative path, it was causing #8664
3174  //QFileInfo myInfo( name );
3175  //QString myFileName = myInfo.fileName(); // foo.svg
3176  //QString myLowestDir = myInfo.dir().dirName();
3177  //QString myLocalPath = svgPath + QString( myLowestDir.isEmpty() ? "" : "/" + myLowestDir ) + "/" + myFileName;
3178  QString myLocalPath = svgPath + QDir::separator() + name;
3179 
3180  QgsDebugMsg( "Alternative svg path: " + myLocalPath );
3181  if ( QFile( myLocalPath ).exists() )
3182  {
3183  QgsDebugMsg( "Svg found in alternative path" );
3184  return QFileInfo( myLocalPath ).canonicalFilePath();
3185  }
3186  }
3187 
3188  QFileInfo pfi( QgsProject::instance()->fileName() );
3189  QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
3190  if ( pfi.exists() && QFile( alternatePath ).exists() )
3191  {
3192  QgsDebugMsg( "Svg found in alternative path" );
3193  return QFileInfo( alternatePath ).canonicalFilePath();
3194  }
3195  else
3196  {
3197  QgsDebugMsg( "Svg not found in project path" );
3198  }
3199  //couldnt find the file, no happy ending :-(
3200  QgsDebugMsg( "Computed alternate path but no svg there either" );
3201 
3202  return QString();
3203 }
3204 
3206 {
3207  // copied from QgsSymbol::writeXML
3208 
3209  QFileInfo fi( path );
3210  if ( !fi.exists() )
3211  return path;
3212 
3213  path = fi.canonicalFilePath();
3214 
3215  QStringList svgPaths = QgsApplication::svgPaths();
3216 
3217  bool isInSvgPathes = false;
3218  for ( int i = 0; i < svgPaths.size(); i++ )
3219  {
3220  QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
3221 
3222  if ( !dir.isEmpty() && path.startsWith( dir ) )
3223  {
3224  path = path.mid( dir.size() + 1 );
3225  isInSvgPathes = true;
3226  break;
3227  }
3228  }
3229 
3230  if ( isInSvgPathes )
3231  return path;
3232 
3233  return QgsProject::instance()->writePath( path );
3234 }
3235 
3236 QPointF QgsSymbolLayerV2Utils::polygonCentroid( const QPolygonF& points )
3237 {
3238  //Calculate the centroid of points
3239  double cx = 0, cy = 0;
3240  double area, sum = 0;
3241  for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
3242  {
3243  const QPointF& p1 = points[i];
3244  const QPointF& p2 = points[j];
3245  area = p1.x() * p2.y() - p1.y() * p2.x();
3246  sum += area;
3247  cx += ( p1.x() + p2.x() ) * area;
3248  cy += ( p1.y() + p2.y() ) * area;
3249  }
3250  sum *= 3.0;
3251  cx /= sum;
3252  cy /= sum;
3253 
3254  return QPointF( cx, cy );
3255 }
3256 
3257 QPointF QgsSymbolLayerV2Utils::polygonPointOnSurface( const QPolygonF& points )
3258 {
3259  QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
3260 
3261  // check if centroid inside in polygon
3262  if ( !QgsSymbolLayerV2Utils::pointInPolygon( points, centroid ) )
3263  {
3264  unsigned int i, pointCount = points.count();
3265 
3266  QgsPolyline polyline( pointCount );
3267  for ( i = 0; i < pointCount; ++i ) polyline[i] = QgsPoint( points[i].x(), points[i].y() );
3268 
3269  QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << polyline );
3270  if ( geom )
3271  {
3272  QgsGeometry* pointOnSurfaceGeom = geom->pointOnSurface();
3273 
3274  if ( pointOnSurfaceGeom )
3275  {
3276  QgsPoint point = pointOnSurfaceGeom->asPoint();
3277  delete pointOnSurfaceGeom;
3278  delete geom;
3279 
3280  return QPointF( point.x(), point.y() );
3281  }
3282  delete geom;
3283  }
3284  }
3285  return centroid;
3286 }
3287 
3288 bool QgsSymbolLayerV2Utils::pointInPolygon( const QPolygonF &points, const QPointF &point )
3289 {
3290  bool inside = false;
3291 
3292  double x = point.x();
3293  double y = point.y();
3294 
3295  for ( int i = 0, j = points.count() - 1; i < points.count(); i++ )
3296  {
3297  const QPointF& p1 = points[i];
3298  const QPointF& p2 = points[j];
3299 
3300  if ( p1.x() == x && p1.y() == y )
3301  return true;
3302 
3303  if (( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
3304  {
3305  if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() )*( p2.x() - p1.x() ) <= x )
3306  inside = !inside;
3307  }
3308 
3309  j = i;
3310  }
3311  return inside;
3312 }
3313 
3315 {
3316  if ( fieldOrExpression.isEmpty() )
3317  return 0;
3318 
3319  QgsExpression* expr = new QgsExpression( fieldOrExpression );
3320  if ( !expr->hasParserError() )
3321  return expr;
3322 
3323  // now try with quoted field name
3324  delete expr;
3325  QgsExpression* expr2 = new QgsExpression( QgsExpression::quotedColumnRef( fieldOrExpression ) );
3326  Q_ASSERT( !expr2->hasParserError() );
3327  return expr2;
3328 }
3329 
3331 {
3332  const QgsExpression::Node* n = expression->rootNode();
3333 
3334  if ( n && n->nodeType() == QgsExpression::ntColumnRef )
3335  return static_cast<const QgsExpression::NodeColumnRef*>( n )->name();
3336 
3337  return expression->expression();
3338 }
3339 
3340 
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:38
static QString encodeSldLineJoinStyle(Qt::PenJoinStyle style)
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
static Qt::BrushStyle decodeBrushStyle(QString str)
void setLocked(bool locked)
static QgsSymbolV2Map loadSymbols(QDomElement &element)
static Qt::PenCapStyle decodeSldLineCapStyle(QString str)
virtual NodeType nodeType() const =0
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:96
QgsSymbolLayerV2 * createSymbolLayer(QString name, const QgsStringMap &properties=QgsStringMap()) const
create a new instance of symbol layer given symbol layer name and properties
static QIcon colorRampPreviewIcon(QgsVectorColorRampV2 *ramp, QSize size)
virtual QString type() const =0
static 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
void drawPreviewIcon(QPainter *painter, QSize size)
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)
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 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 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:125
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
static QColor parseColor(QString colorStr)
Attempts to parse a string as a color using a variety of common formats, including hex codes...
QVector< QgsPolyline > QgsMultiPolyline
a collection of QgsPolylines that share a common collection of attributes
Definition: qgsgeometry.h:50
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 QColor parseColorWithAlpha(const QString colorStr, bool &containsAlpha)
Attempts to parse a string as a color 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.
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:127
static void blurImageInPlace(QImage &image, const QRect &rect, int radius, bool alphaOnly)
Blurs an image in place, e.g.
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
static QString encodeSldLineCapStyle(Qt::PenCapStyle style)
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, QString path, QString format, int *markIndex=0, QColor color=QColor(), double size=-1)
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
static bool needEllipseMarker(QDomElement &element)
static QString encodePenCapStyle(Qt::PenCapStyle style)