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