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