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