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