00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "qgssymbollayerv2utils.h"
00017
00018 #include "qgssymbollayerv2.h"
00019 #include "qgssymbollayerv2registry.h"
00020 #include "qgssymbolv2.h"
00021 #include "qgsvectorcolorrampv2.h"
00022 #include "qgsexpression.h"
00023
00024 #include "qgslogger.h"
00025 #include "qgsrendercontext.h"
00026
00027 #include <QColor>
00028 #include <QFont>
00029 #include <QDomDocument>
00030 #include <QDomNode>
00031 #include <QDomElement>
00032 #include <QIcon>
00033 #include <QPainter>
00034
00035 QString QgsSymbolLayerV2Utils::encodeColor( QColor color )
00036 {
00037 return QString( "%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
00038 }
00039
00040 QColor QgsSymbolLayerV2Utils::decodeColor( QString str )
00041 {
00042 QStringList lst = str.split( "," );
00043 if ( lst.count() < 3 )
00044 {
00045 return QColor();
00046 }
00047 int red, green, blue, alpha;
00048 red = lst[0].toInt();
00049 green = lst[1].toInt();
00050 blue = lst[2].toInt();
00051 alpha = 255;
00052 if ( lst.count() > 3 )
00053 {
00054 alpha = lst[3].toInt();
00055 }
00056 return QColor( red, green, blue, alpha );
00057 }
00058
00059 QString QgsSymbolLayerV2Utils::encodeSldAlpha( int alpha )
00060 {
00061 return QString::number( alpha / 255.0, 'f', 2 );
00062 }
00063
00064 int QgsSymbolLayerV2Utils::decodeSldAlpha( QString str )
00065 {
00066 bool ok;
00067 double alpha = str.toDouble( &ok );
00068 if ( !ok || alpha > 1 )
00069 alpha = 255;
00070 else if ( alpha < 0 )
00071 alpha = 0;
00072 return alpha * 255;
00073 }
00074
00075 QString QgsSymbolLayerV2Utils::encodeSldFontStyle( QFont::Style style )
00076 {
00077 switch ( style )
00078 {
00079 case QFont::StyleNormal: return "normal";
00080 case QFont::StyleItalic: return "italic";
00081 case QFont::StyleOblique: return "oblique";
00082 default: return "";
00083 }
00084 }
00085
00086 QFont::Style QgsSymbolLayerV2Utils::decodeSldFontStyle( QString str )
00087 {
00088 if ( str == "normal" ) return QFont::StyleNormal;
00089 if ( str == "italic" ) return QFont::StyleItalic;
00090 if ( str == "oblique" ) return QFont::StyleOblique;
00091 return QFont::StyleNormal;
00092 }
00093
00094 QString QgsSymbolLayerV2Utils::encodeSldFontWeight( int weight )
00095 {
00096 if ( weight == 50 ) return "normal";
00097 if ( weight == 75 ) return "bold";
00098
00099
00100
00101 if ( weight < 0 ) return "100";
00102 if ( weight > 99 ) return "900";
00103 return QString::number( weight * 800 / 99 + 100 );
00104 }
00105
00106 int QgsSymbolLayerV2Utils::decodeSldFontWeight( QString str )
00107 {
00108 bool ok;
00109 int weight = str.toInt( &ok );
00110 if ( !ok ) return ( int ) QFont::Normal;
00111
00112
00113
00114 if ( weight > 900 ) return 99;
00115 if ( weight < 100 ) return 0;
00116 return ( weight - 100 ) * 99 / 800;
00117 }
00118
00119 QString QgsSymbolLayerV2Utils::encodePenStyle( Qt::PenStyle style )
00120 {
00121 switch ( style )
00122 {
00123 case Qt::NoPen: return "no";
00124 case Qt::SolidLine: return "solid";
00125 case Qt::DashLine: return "dash";
00126 case Qt::DotLine: return "dot";
00127 case Qt::DashDotLine: return "dash dot";
00128 case Qt::DashDotDotLine: return "dash dot dot";
00129 default: return "???";
00130 }
00131 }
00132
00133 Qt::PenStyle QgsSymbolLayerV2Utils::decodePenStyle( QString str )
00134 {
00135 if ( str == "no" ) return Qt::NoPen;
00136 if ( str == "solid" ) return Qt::SolidLine;
00137 if ( str == "dash" ) return Qt::DashLine;
00138 if ( str == "dot" ) return Qt::DotLine;
00139 if ( str == "dash dot" ) return Qt::DashDotLine;
00140 if ( str == "dash dot dot" ) return Qt::DashDotDotLine;
00141 return Qt::SolidLine;
00142 }
00143
00144 QString QgsSymbolLayerV2Utils::encodePenJoinStyle( Qt::PenJoinStyle style )
00145 {
00146 switch ( style )
00147 {
00148 case Qt::BevelJoin: return "bevel";
00149 case Qt::MiterJoin: return "miter";
00150 case Qt::RoundJoin: return "round";
00151 default: return "???";
00152 }
00153 }
00154
00155 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodePenJoinStyle( QString str )
00156 {
00157 if ( str == "bevel" ) return Qt::BevelJoin;
00158 if ( str == "miter" ) return Qt::MiterJoin;
00159 if ( str == "round" ) return Qt::RoundJoin;
00160 return Qt::BevelJoin;
00161 }
00162
00163 QString QgsSymbolLayerV2Utils::encodeSldLineJoinStyle( Qt::PenJoinStyle style )
00164 {
00165 switch ( style )
00166 {
00167 case Qt::BevelJoin: return "bevel";
00168 case Qt::MiterJoin: return "mitre";
00169 case Qt::RoundJoin: return "round";
00170 default: return "";
00171 }
00172 }
00173
00174 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodeSldLineJoinStyle( QString str )
00175 {
00176 if ( str == "bevel" ) return Qt::BevelJoin;
00177 if ( str == "mitre" ) return Qt::MiterJoin;
00178 if ( str == "round" ) return Qt::RoundJoin;
00179 return Qt::BevelJoin;
00180 }
00181
00182 QString QgsSymbolLayerV2Utils::encodePenCapStyle( Qt::PenCapStyle style )
00183 {
00184 switch ( style )
00185 {
00186 case Qt::SquareCap: return "square";
00187 case Qt::FlatCap: return "flat";
00188 case Qt::RoundCap: return "round";
00189 default: return "???";
00190 }
00191 }
00192
00193 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodePenCapStyle( QString str )
00194 {
00195 if ( str == "square" ) return Qt::SquareCap;
00196 if ( str == "flat" ) return Qt::FlatCap;
00197 if ( str == "round" ) return Qt::RoundCap;
00198 return Qt::SquareCap;
00199 }
00200
00201 QString QgsSymbolLayerV2Utils::encodeSldLineCapStyle( Qt::PenCapStyle style )
00202 {
00203 switch ( style )
00204 {
00205 case Qt::SquareCap: return "square";
00206 case Qt::FlatCap: return "butt";
00207 case Qt::RoundCap: return "round";
00208 default: return "";
00209 }
00210 }
00211
00212 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodeSldLineCapStyle( QString str )
00213 {
00214 if ( str == "square" ) return Qt::SquareCap;
00215 if ( str == "butt" ) return Qt::FlatCap;
00216 if ( str == "round" ) return Qt::RoundCap;
00217 return Qt::SquareCap;
00218 }
00219
00220 QString QgsSymbolLayerV2Utils::encodeBrushStyle( Qt::BrushStyle style )
00221 {
00222 switch ( style )
00223 {
00224 case Qt::SolidPattern : return "solid";
00225 case Qt::HorPattern : return "horizontal";
00226 case Qt::VerPattern : return "vertical";
00227 case Qt::CrossPattern : return "cross";
00228 case Qt::BDiagPattern : return "b_diagonal";
00229 case Qt::FDiagPattern : return "f_diagonal";
00230 case Qt::DiagCrossPattern : return "diagonal_x";
00231 case Qt::Dense1Pattern : return "dense1";
00232 case Qt::Dense2Pattern : return "dense2";
00233 case Qt::Dense3Pattern : return "dense3";
00234 case Qt::Dense4Pattern : return "dense4";
00235 case Qt::Dense5Pattern : return "dense5";
00236 case Qt::Dense6Pattern : return "dense6";
00237 case Qt::Dense7Pattern : return "dense7";
00238 case Qt::NoBrush : return "no";
00239 default: return "???";
00240 }
00241 }
00242
00243 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeBrushStyle( QString str )
00244 {
00245 if ( str == "solid" ) return Qt::SolidPattern;
00246 if ( str == "horizontal" ) return Qt::HorPattern;
00247 if ( str == "vertical" ) return Qt::VerPattern;
00248 if ( str == "cross" ) return Qt::CrossPattern;
00249 if ( str == "b_diagonal" ) return Qt::BDiagPattern;
00250 if ( str == "f_diagonal" ) return Qt::FDiagPattern;
00251 if ( str == "diagonal_x" ) return Qt::DiagCrossPattern;
00252 if ( str == "dense1" ) return Qt::Dense1Pattern;
00253 if ( str == "dense2" ) return Qt::Dense2Pattern;
00254 if ( str == "dense3" ) return Qt::Dense3Pattern;
00255 if ( str == "dense4" ) return Qt::Dense4Pattern;
00256 if ( str == "dense5" ) return Qt::Dense5Pattern;
00257 if ( str == "dense6" ) return Qt::Dense6Pattern;
00258 if ( str == "dense7" ) return Qt::Dense7Pattern;
00259 if ( str == "no" ) return Qt::NoBrush;
00260 return Qt::SolidPattern;
00261 }
00262
00263 QString QgsSymbolLayerV2Utils::encodeSldBrushStyle( Qt::BrushStyle style )
00264 {
00265 switch ( style )
00266 {
00267 case Qt::CrossPattern: return "cross";
00268 case Qt::DiagCrossPattern: return "x";
00269
00270
00271
00272
00273
00274 case Qt::HorPattern: return "horline";
00275 case Qt::VerPattern: return "line";
00276 case Qt::BDiagPattern: return "slash";
00277 case Qt::FDiagPattern: return "backslash";
00278
00279
00280 case Qt::Dense1Pattern:
00281 case Qt::Dense2Pattern:
00282 case Qt::Dense3Pattern:
00283 case Qt::Dense4Pattern:
00284 case Qt::Dense5Pattern:
00285 case Qt::Dense6Pattern:
00286 case Qt::Dense7Pattern:
00287 return QString( "brush://%1" ).arg( encodeBrushStyle( style ) );
00288
00289 default:
00290 return QString();
00291 }
00292 }
00293
00294 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeSldBrushStyle( QString str )
00295 {
00296 if ( str == "horline" ) return Qt::HorPattern;
00297 if ( str == "line" ) return Qt::VerPattern;
00298 if ( str == "cross" ) return Qt::CrossPattern;
00299 if ( str == "slash" ) return Qt::BDiagPattern;
00300 if ( str == "backshash" ) return Qt::FDiagPattern;
00301 if ( str == "x" ) return Qt::DiagCrossPattern;
00302
00303 if ( str.startsWith( "brush://" ) )
00304 return decodeBrushStyle( str.mid( 8 ) );
00305
00306 return Qt::NoBrush;
00307 }
00308
00309 QString QgsSymbolLayerV2Utils::encodePoint( QPointF point )
00310 {
00311 return QString( "%1,%2" ).arg( point.x() ).arg( point.y() );
00312 }
00313
00314 QPointF QgsSymbolLayerV2Utils::decodePoint( QString str )
00315 {
00316 QStringList lst = str.split( ',' );
00317 if ( lst.count() != 2 )
00318 return QPointF( 0, 0 );
00319 return QPointF( lst[0].toDouble(), lst[1].toDouble() );
00320 }
00321
00322 QString QgsSymbolLayerV2Utils::encodeOutputUnit( QgsSymbolV2::OutputUnit unit )
00323 {
00324 switch ( unit )
00325 {
00326 case QgsSymbolV2::MM:
00327 return "MM";
00328 case QgsSymbolV2::MapUnit:
00329 return "MapUnit";
00330 default:
00331 return "MM";
00332 }
00333 }
00334
00335 QgsSymbolV2::OutputUnit QgsSymbolLayerV2Utils::decodeOutputUnit( QString str )
00336 {
00337 if ( str == "MM" )
00338 {
00339 return QgsSymbolV2::MM;
00340 }
00341 else if ( str == "MapUnit" )
00342 {
00343 return QgsSymbolV2::MapUnit;
00344 }
00345
00346
00347 return QgsSymbolV2::MM;
00348 }
00349
00350 QString QgsSymbolLayerV2Utils::encodeSldUom( QgsSymbolV2::OutputUnit unit, double *scaleFactor )
00351 {
00352 switch ( unit )
00353 {
00354 case QgsSymbolV2::MapUnit:
00355 if ( scaleFactor )
00356 *scaleFactor = 0.001;
00357 return "http://www.opengeospatial.org/se/units/metre";
00358
00359 case QgsSymbolV2::MM:
00360 default:
00361
00362
00363 if ( scaleFactor )
00364 *scaleFactor = 0.28;
00365
00366
00367 return QString();
00368 }
00369 }
00370
00371 QgsSymbolV2::OutputUnit QgsSymbolLayerV2Utils::decodeSldUom( QString str, double *scaleFactor )
00372 {
00373 if ( str == "http://www.opengeospatial.org/se/units/metre" )
00374 {
00375 if ( scaleFactor )
00376 *scaleFactor = 1000.0;
00377 return QgsSymbolV2::MapUnit;
00378 }
00379 else if ( str == "http://www.opengeospatial.org/se/units/foot" )
00380 {
00381 if ( scaleFactor )
00382 *scaleFactor = 304.8;
00383 return QgsSymbolV2::MapUnit;
00384 }
00385
00386
00387
00388 if ( scaleFactor )
00389 *scaleFactor = 1 / 0.00028;
00390 return QgsSymbolV2::MM;
00391 }
00392
00393 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
00394 {
00395 QString vectorString;
00396 QVector<qreal>::const_iterator it = v.constBegin();
00397 for ( ; it != v.constEnd(); ++it )
00398 {
00399 if ( it != v.constBegin() )
00400 {
00401 vectorString.append( ";" );
00402 }
00403 vectorString.append( QString::number( *it ) );
00404 }
00405 return vectorString;
00406 }
00407
00408 QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
00409 {
00410 QVector<qreal> resultVector;
00411
00412 QStringList realList = s.split( ";" );
00413 QStringList::const_iterator it = realList.constBegin();
00414 for ( ; it != realList.constEnd(); ++it )
00415 {
00416 resultVector.append( it->toDouble() );
00417 }
00418
00419 return resultVector;
00420 }
00421
00422 QString QgsSymbolLayerV2Utils::encodeSldRealVector( const QVector<qreal>& v )
00423 {
00424 QString vectorString;
00425 QVector<qreal>::const_iterator it = v.constBegin();
00426 for ( ; it != v.constEnd(); ++it )
00427 {
00428 if ( it != v.constBegin() )
00429 {
00430 vectorString.append( " " );
00431 }
00432 vectorString.append( QString::number( *it ) );
00433 }
00434 return vectorString;
00435 }
00436
00437 QVector<qreal> QgsSymbolLayerV2Utils::decodeSldRealVector( const QString& s )
00438 {
00439 QVector<qreal> resultVector;
00440
00441 QStringList realList = s.split( " " );
00442 QStringList::const_iterator it = realList.constBegin();
00443 for ( ; it != realList.constEnd(); ++it )
00444 {
00445 resultVector.append( it->toDouble() );
00446 }
00447
00448 return resultVector;
00449 }
00450
00451 QIcon QgsSymbolLayerV2Utils::symbolPreviewIcon( QgsSymbolV2* symbol, QSize size )
00452 {
00453 return QIcon( symbolPreviewPixmap( symbol, size ) );
00454 }
00455
00456 QPixmap QgsSymbolLayerV2Utils::symbolPreviewPixmap( QgsSymbolV2* symbol, QSize size )
00457 {
00458 Q_ASSERT( symbol );
00459
00460 QPixmap pixmap( size );
00461 pixmap.fill( Qt::transparent );
00462 QPainter painter;
00463 painter.begin( &pixmap );
00464 painter.setRenderHint( QPainter::Antialiasing );
00465 symbol->drawPreviewIcon( &painter, size );
00466 painter.end();
00467 return pixmap;
00468 }
00469
00470
00471 QIcon QgsSymbolLayerV2Utils::symbolLayerPreviewIcon( QgsSymbolLayerV2* layer, QgsSymbolV2::OutputUnit u, QSize size )
00472 {
00473 QPixmap pixmap( size );
00474 pixmap.fill( Qt::transparent );
00475 QPainter painter;
00476 painter.begin( &pixmap );
00477 painter.setRenderHint( QPainter::Antialiasing );
00478 QgsRenderContext renderContext = createRenderContext( &painter );
00479 QgsSymbolV2RenderContext symbolContext( renderContext, u );
00480 layer->drawPreviewIcon( symbolContext, size );
00481 painter.end();
00482 return QIcon( pixmap );
00483 }
00484
00485 QIcon QgsSymbolLayerV2Utils::colorRampPreviewIcon( QgsVectorColorRampV2* ramp, QSize size )
00486 {
00487 return QIcon( colorRampPreviewPixmap( ramp, size ) );
00488 }
00489
00490 QPixmap QgsSymbolLayerV2Utils::colorRampPreviewPixmap( QgsVectorColorRampV2* ramp, QSize size )
00491 {
00492 QPixmap pixmap( size );
00493 QPainter painter;
00494 painter.begin( &pixmap );
00495 painter.setRenderHint( QPainter::Antialiasing );
00496 painter.eraseRect( QRect( QPoint( 0, 0 ), size ) );
00497 for ( int i = 0; i < size.width(); i++ )
00498 {
00499 QPen pen( ramp->color(( double ) i / size.width() ) );
00500 painter.setPen( pen );
00501 painter.drawLine( i, 0, i, size.height() - 1 );
00502 }
00503 painter.end();
00504 return pixmap;
00505 }
00506
00507
00508 #include <QPolygonF>
00509
00510 #include <cmath>
00511 #include <cfloat>
00512
00513
00514
00515 static bool lineInfo( QPointF p1, QPointF p2, double& angle, double& t )
00516 {
00517 double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();
00518
00519 if ( x1 == x2 && y1 == y2 )
00520 return false;
00521
00522
00523 t = ( x1 == x2 ? DBL_MAX : ( y2 - y1 ) / ( x2 - x1 ) );
00524
00525
00526 if ( t == DBL_MAX )
00527 angle = ( y2 > y1 ? M_PI / 2 : M_PI * 3 / 2 );
00528 else if ( t == 0 )
00529 angle = ( x2 > x1 ? 0 : M_PI );
00530 else if ( t >= 0 )
00531 angle = ( y2 > y1 ? atan( t ) : M_PI + atan( t ) );
00532 else
00533 angle = ( y2 > y1 ? M_PI + atan( t ) : atan( t ) );
00534
00535 return true;
00536 }
00537
00538
00539 static QPointF offsetPoint( QPointF pt, double angle, double dist )
00540 {
00541 return QPointF( pt.x() + dist * cos( angle ), pt.y() + dist * sin( angle ) );
00542 }
00543
00544
00545 static QPointF linesIntersection( QPointF p1, double t1, QPointF p2, double t2 )
00546 {
00547
00548 if (( t1 == DBL_MAX && t2 == DBL_MAX ) || qAbs( t1 - t2 ) < 0.001 )
00549 return QPointF();
00550
00551 double x, y;
00552 if ( t1 == DBL_MAX || t2 == DBL_MAX )
00553 {
00554
00555
00556 if ( t1 == DBL_MAX )
00557 {
00558 QPointF pSwp = p1; p1 = p2; p2 = pSwp;
00559 double tSwp = t1; t1 = t2; t2 = tSwp;
00560 }
00561
00562 x = p2.x();
00563 }
00564 else
00565 {
00566
00567 x = (( p1.y() - p2.y() ) + t2 * p2.x() - t1 * p1.x() ) / ( t2 - t1 );
00568 }
00569
00570 y = p1.y() + t1 * ( x - p1.x() );
00571 return QPointF( x, y );
00572 }
00573
00574
00575 QPolygonF offsetLine( QPolygonF polyline, double dist )
00576 {
00577 QPolygonF newLine;
00578
00579 if ( polyline.count() < 2 )
00580 return newLine;
00581
00582 double angle = 0.0, t_new, t_old = 0;
00583 QPointF pt_old, pt_new;
00584 QPointF p1 = polyline[0], p2;
00585 bool first_point = true;
00586
00587 for ( int i = 1; i < polyline.count(); i++ )
00588 {
00589 p2 = polyline[i];
00590
00591 if ( !lineInfo( p1, p2, angle, t_new ) )
00592 continue;
00593
00594 pt_new = offsetPoint( p1, angle + M_PI / 2, dist );
00595
00596 if ( ! first_point )
00597 {
00598
00599
00600 QPointF pt_tmp = linesIntersection( pt_old, t_old, pt_new, t_new );
00601 if ( !pt_tmp.isNull() )
00602 pt_new = pt_tmp;
00603 }
00604
00605 newLine.append( pt_new );
00606
00607 pt_old = pt_new;
00608 t_old = t_new;
00609 p1 = p2;
00610 first_point = false;
00611 }
00612
00613
00614 pt_new = offsetPoint( p2, angle + M_PI / 2, dist );
00615 newLine.append( pt_new );
00616 return newLine;
00617 }
00618
00620
00621
00622 QgsSymbolV2* QgsSymbolLayerV2Utils::loadSymbol( QDomElement& element )
00623 {
00624 QgsSymbolLayerV2List layers;
00625 QDomNode layerNode = element.firstChild();
00626
00627 while ( !layerNode.isNull() )
00628 {
00629 QDomElement e = layerNode.toElement();
00630 if ( !e.isNull() )
00631 {
00632 if ( e.tagName() != "layer" )
00633 {
00634 QgsDebugMsg( "unknown tag " + e.tagName() );
00635 }
00636 else
00637 {
00638 QgsSymbolLayerV2* layer = loadSymbolLayer( e );
00639 if ( layer != NULL )
00640 layers.append( layer );
00641 }
00642 }
00643 layerNode = layerNode.nextSibling();
00644 }
00645
00646 if ( layers.count() == 0 )
00647 {
00648 QgsDebugMsg( "no layers for symbol" );
00649 return NULL;
00650 }
00651
00652 QString symbolType = element.attribute( "type" );
00653
00654 QgsSymbolV2* symbol = 0;
00655 if ( symbolType == "line" )
00656 symbol = new QgsLineSymbolV2( layers );
00657 else if ( symbolType == "fill" )
00658 symbol = new QgsFillSymbolV2( layers );
00659 else if ( symbolType == "marker" )
00660 symbol = new QgsMarkerSymbolV2( layers );
00661 else
00662 {
00663 QgsDebugMsg( "unknown symbol type " + symbolType );
00664 return NULL;
00665 }
00666
00667 symbol->setOutputUnit( decodeOutputUnit( element.attribute( "outputUnit" ) ) );
00668 symbol->setAlpha( element.attribute( "alpha", "1.0" ).toDouble() );
00669
00670 return symbol;
00671 }
00672
00673 QgsSymbolLayerV2* QgsSymbolLayerV2Utils::loadSymbolLayer( QDomElement& element )
00674 {
00675 QString layerClass = element.attribute( "class" );
00676 bool locked = element.attribute( "locked" ).toInt();
00677 int pass = element.attribute( "pass" ).toInt();
00678
00679
00680 QgsStringMap props = parseProperties( element );
00681
00682 QgsSymbolLayerV2* layer;
00683 layer = QgsSymbolLayerV2Registry::instance()->createSymbolLayer( layerClass, props );
00684 if ( layer )
00685 {
00686 layer->setLocked( locked );
00687 layer->setRenderingPass( pass );
00688 return layer;
00689 }
00690 else
00691 {
00692 QgsDebugMsg( "unknown class " + layerClass );
00693 return NULL;
00694 }
00695 }
00696
00697 static QString _nameForSymbolType( QgsSymbolV2::SymbolType type )
00698 {
00699 switch ( type )
00700 {
00701 case QgsSymbolV2::Line: return "line";
00702 case QgsSymbolV2::Marker: return "marker";
00703 case QgsSymbolV2::Fill: return "fill";
00704 default: return "";
00705 }
00706 }
00707
00708 QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc, QgsSymbolV2Map* subSymbols )
00709 {
00710 Q_ASSERT( symbol );
00711
00712 QDomElement symEl = doc.createElement( "symbol" );
00713 symEl.setAttribute( "type", _nameForSymbolType( symbol->type() ) );
00714 symEl.setAttribute( "name", name );
00715 symEl.setAttribute( "outputUnit", encodeOutputUnit( symbol->outputUnit() ) );
00716 symEl.setAttribute( "alpha", symbol->alpha() );
00717 QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
00718 for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
00719 {
00720 QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
00721
00722 QDomElement layerEl = doc.createElement( "layer" );
00723 layerEl.setAttribute( "class", layer->layerType() );
00724 layerEl.setAttribute( "locked", layer->isLocked() );
00725 layerEl.setAttribute( "pass", layer->renderingPass() );
00726
00727 if ( subSymbols != NULL && layer->subSymbol() != NULL )
00728 {
00729 QString subname = QString( "@%1@%2" ).arg( name ).arg( i );
00730 subSymbols->insert( subname, layer->subSymbol() );
00731 }
00732
00733 saveProperties( layer->properties(), doc, layerEl );
00734 symEl.appendChild( layerEl );
00735 }
00736
00737 return symEl;
00738 }
00739
00740
00741 bool QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( QDomElement& element,
00742 QGis::GeometryType geomType,
00743 QgsSymbolLayerV2List &layers )
00744 {
00745 QgsDebugMsg( "Entered." );
00746
00747 if ( element.isNull() )
00748 return false;
00749
00750 QgsSymbolLayerV2 *l = 0;
00751
00752 QString symbolizerName = element.localName();
00753
00754 if ( symbolizerName == "PointSymbolizer" )
00755 {
00756
00757 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00758 if ( graphicElem.isNull() )
00759 {
00760 QgsDebugMsg( "Graphic element not found in PointSymbolizer" );
00761 }
00762 else
00763 {
00764 switch ( geomType )
00765 {
00766 case QGis::Polygon:
00767
00768 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "CentroidFill", element );
00769 if ( l )
00770 layers.append( l );
00771
00772 break;
00773
00774 case QGis::Point:
00775
00776 l = createMarkerLayerFromSld( element );
00777 if ( l )
00778 layers.append( l );
00779
00780 break;
00781
00782 case QGis::Line:
00783
00784 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
00785 if ( l )
00786 layers.append( l );
00787
00788 break;
00789
00790 default:
00791 break;
00792 }
00793 }
00794 }
00795
00796 if ( symbolizerName == "LineSymbolizer" )
00797 {
00798
00799 QDomElement strokeElem = element.firstChildElement( "Stroke" );
00800 if ( strokeElem.isNull() )
00801 {
00802 QgsDebugMsg( "Stroke element not found in LineSymbolizer" );
00803 }
00804 else
00805 {
00806 switch ( geomType )
00807 {
00808 case QGis::Polygon:
00809 case QGis::Line:
00810
00811
00812 l = createLineLayerFromSld( element );
00813 if ( l )
00814 layers.append( l );
00815
00816 break;
00817
00818 case QGis::Point:
00819
00820 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
00821 if ( l )
00822 layers.append( l );
00823
00824 default:
00825 break;
00826 }
00827 }
00828 }
00829
00830 if ( symbolizerName == "PolygonSymbolizer" )
00831 {
00832
00833 QDomElement fillElem = element.firstChildElement( "Fill" );
00834 QDomElement strokeElem = element.firstChildElement( "Stroke" );
00835 if ( fillElem.isNull() && strokeElem.isNull() )
00836 {
00837 QgsDebugMsg( "neither Fill nor Stroke element not found in PolygonSymbolizer" );
00838 }
00839 else
00840 {
00841 QgsSymbolLayerV2 *l = 0;
00842
00843 switch ( geomType )
00844 {
00845 case QGis::Polygon:
00846
00847
00848 l = createFillLayerFromSld( element );
00849 if ( l )
00850 {
00851 layers.append( l );
00852
00853
00854
00855 if ( l->layerType() == "SimpleFill" || l->layerType() == "SVGFill" )
00856 break;
00857 }
00858
00859
00860
00861 l = createLineLayerFromSld( element );
00862 if ( l )
00863 layers.append( l );
00864
00865 break;
00866
00867 case QGis::Line:
00868
00869 l = createLineLayerFromSld( element );
00870 if ( l )
00871 layers.append( l );
00872
00873 break;
00874
00875 case QGis::Point:
00876
00877 convertPolygonSymbolizerToPointMarker( element, layers );
00878 break;
00879
00880 default:
00881 break;
00882 }
00883 }
00884 }
00885
00886 return true;
00887 }
00888
00889 QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createFillLayerFromSld( QDomElement &element )
00890 {
00891 QDomElement fillElem = element.firstChildElement( "Fill" );
00892 if ( fillElem.isNull() )
00893 {
00894 QgsDebugMsg( "Fill element not found" );
00895 return NULL;
00896 }
00897
00898 QgsSymbolLayerV2 *l = 0;
00899
00900 if ( needLinePatternFill( element ) )
00901 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "LinePatternFill", element );
00902 else if ( needPointPatternFill( element ) )
00903 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "PointPatternFill", element );
00904 else if ( needSvgFill( element ) )
00905 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SVGFill", element );
00906 else
00907 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleFill", element );
00908
00909 return l;
00910 }
00911
00912 QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createLineLayerFromSld( QDomElement &element )
00913 {
00914 QDomElement strokeElem = element.firstChildElement( "Stroke" );
00915 if ( strokeElem.isNull() )
00916 {
00917 QgsDebugMsg( "Stroke element not found" );
00918 return NULL;
00919 }
00920
00921 QgsSymbolLayerV2 *l = 0;
00922
00923 if ( needMarkerLine( element ) )
00924 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
00925 else
00926 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleLine", element );
00927
00928 return l;
00929 }
00930
00931 QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createMarkerLayerFromSld( QDomElement &element )
00932 {
00933 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00934 if ( graphicElem.isNull() )
00935 {
00936 QgsDebugMsg( "Graphic element not found" );
00937 return NULL;
00938 }
00939
00940 QgsSymbolLayerV2 *l = 0;
00941
00942 if ( needFontMarker( element ) )
00943 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "FontMarker", element );
00944 else if ( needSvgMarker( element ) )
00945 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SvgMarker", element );
00946 else if ( needEllipseMarker( element ) )
00947 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "EllipseMarker", element );
00948 else
00949 l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
00950
00951 return l;
00952 }
00953
00954 bool QgsSymbolLayerV2Utils::hasExternalGraphic( QDomElement &element )
00955 {
00956 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00957 if ( graphicElem.isNull() )
00958 return false;
00959
00960 QDomElement externalGraphicElem = graphicElem.firstChildElement( "ExternalGraphic" );
00961 if ( externalGraphicElem.isNull() )
00962 return false;
00963
00964
00965 QDomElement formatElem = externalGraphicElem.firstChildElement( "Format" );
00966 if ( formatElem.isNull() )
00967 return false;
00968
00969 QString format = formatElem.firstChild().nodeValue();
00970 if ( format != "image/svg+xml" )
00971 {
00972 QgsDebugMsg( "unsupported External Graphic format found: " + format );
00973 return false;
00974 }
00975
00976
00977 QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( "OnlineResource" );
00978 QDomElement inlineContentElem = externalGraphicElem.firstChildElement( "InlineContent" );
00979 if ( !onlineResourceElem.isNull() )
00980 {
00981 return true;
00982 }
00983 else if ( !inlineContentElem.isNull() )
00984 {
00985 return false;
00986 }
00987 else
00988 {
00989 return false;
00990 }
00991
00992 return false;
00993 }
00994
00995 bool QgsSymbolLayerV2Utils::hasWellKnownMark( QDomElement &element )
00996 {
00997 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00998 if ( graphicElem.isNull() )
00999 return false;
01000
01001 QDomElement markElem = graphicElem.firstChildElement( "Mark" );
01002 if ( markElem.isNull() )
01003 return false;
01004
01005 QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
01006 if ( wellKnownNameElem.isNull() )
01007 return false;
01008
01009 return true;
01010 }
01011
01012
01013 bool QgsSymbolLayerV2Utils::needFontMarker( QDomElement &element )
01014 {
01015 QDomElement graphicElem = element.firstChildElement( "Graphic" );
01016 if ( graphicElem.isNull() )
01017 return false;
01018
01019 QDomElement markElem = graphicElem.firstChildElement( "Mark" );
01020 if ( markElem.isNull() )
01021 return false;
01022
01023
01024 QDomElement formatElem = markElem.firstChildElement( "Format" );
01025 if ( formatElem.isNull() )
01026 return false;
01027
01028 QString format = formatElem.firstChild().nodeValue();
01029 if ( format != "ttf" )
01030 {
01031 QgsDebugMsg( "unsupported Graphic Mark format found: " + format );
01032 return false;
01033 }
01034
01035
01036 QDomElement onlineResourceElem = markElem.firstChildElement( "OnlineResource" );
01037 QDomElement inlineContentElem = markElem.firstChildElement( "InlineContent" );
01038 if ( !onlineResourceElem.isNull() )
01039 {
01040
01041 QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
01042 if ( !markIndexElem.isNull() )
01043 return true;
01044 }
01045 else if ( !inlineContentElem.isNull() )
01046 {
01047 return false;
01048 }
01049
01050 return false;
01051 }
01052
01053 bool QgsSymbolLayerV2Utils::needSvgMarker( QDomElement &element )
01054 {
01055 return hasExternalGraphic( element );
01056 }
01057
01058 bool QgsSymbolLayerV2Utils::needEllipseMarker( QDomElement &element )
01059 {
01060 QDomElement graphicElem = element.firstChildElement( "Graphic" );
01061 if ( graphicElem.isNull() )
01062 return false;
01063
01064 QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
01065 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
01066 {
01067 if ( it.key() == "widthHeightFactor" )
01068 {
01069 return true;
01070 }
01071 }
01072
01073 return false;
01074 }
01075
01076 bool QgsSymbolLayerV2Utils::needMarkerLine( QDomElement &element )
01077 {
01078 QDomElement strokeElem = element.firstChildElement( "Stroke" );
01079 if ( strokeElem.isNull() )
01080 return false;
01081
01082 QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
01083 if ( graphicStrokeElem.isNull() )
01084 return false;
01085
01086 return hasWellKnownMark( graphicStrokeElem );
01087 }
01088
01089 bool QgsSymbolLayerV2Utils::needLinePatternFill( QDomElement &element ) { Q_UNUSED( element ); return false; }
01090 bool QgsSymbolLayerV2Utils::needPointPatternFill( QDomElement &element ) { Q_UNUSED( element ); return false; }
01091
01092 bool QgsSymbolLayerV2Utils::needSvgFill( QDomElement &element )
01093 {
01094 QDomElement fillElem = element.firstChildElement( "Fill" );
01095 if ( fillElem.isNull() )
01096 return false;
01097
01098 QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
01099 if ( graphicFillElem.isNull() )
01100 return false;
01101
01102 return hasExternalGraphic( graphicFillElem );
01103 }
01104
01105
01106 bool QgsSymbolLayerV2Utils::convertPolygonSymbolizerToPointMarker( QDomElement &element, QgsSymbolLayerV2List &layerList )
01107 {
01108 QgsDebugMsg( "Entered." );
01109
01110
01111
01112
01113
01114
01115
01116 QgsSymbolLayerV2List layers;
01117
01118
01119 QDomElement fillElem = element.firstChildElement( "Fill" );
01120 QDomElement strokeElem = element.firstChildElement( "Stroke" );
01121
01122
01123 {
01124 bool validFill = false, validBorder = false;
01125
01126
01127
01128 QColor fillColor;
01129 Qt::BrushStyle fillStyle;
01130
01131 if ( fillFromSld( fillElem, fillStyle, fillColor ) )
01132 validFill = true;
01133
01134
01135
01136 QColor borderColor;
01137 Qt::PenStyle borderStyle;
01138 double borderWidth = 1.0, dashOffset = 0.0;
01139 QVector<qreal> customDashPattern;
01140
01141 if ( lineFromSld( strokeElem, borderStyle, borderColor, borderWidth,
01142 0, 0, &customDashPattern, &dashOffset ) )
01143 validBorder = true;
01144
01145 if ( validFill || validBorder )
01146 {
01147 QgsStringMap map;
01148 map["name"] = "square";
01149 map["color"] = QgsSymbolLayerV2Utils::encodeColor( validFill ? fillColor : Qt::transparent );
01150 map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( validBorder ? borderColor : Qt::transparent );
01151 map["size"] = QString::number( 6 );
01152 map["angle"] = QString::number( 0 );
01153 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( QPointF( 0, 0 ) );
01154 layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SimpleMarker", map ) );
01155 }
01156 }
01157
01158
01159 {
01160 bool validFill = false, validBorder = false;
01161
01162
01163 QString name, format;
01164 int markIndex = -1;
01165 QColor fillColor, borderColor;
01166 double borderWidth = 1, size, angle = 0.0;
01167 QPointF anchor, offset;
01168
01169
01170 QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
01171 if ( !graphicFillElem.isNull() )
01172 {
01173
01174 QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
01175 if ( !graphicElem.isNull() )
01176 {
01177
01178
01179 bool found = false;
01180
01181 QDomElement graphicChildElem = graphicElem.firstChildElement();
01182 while ( !graphicChildElem.isNull() )
01183 {
01184 if ( graphicChildElem.localName() == "Mark" )
01185 {
01186
01187 QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( "WellKnownName" );
01188 if ( !wellKnownNameElem.isNull() )
01189 {
01190 name = wellKnownNameElem.firstChild().nodeValue();
01191 found = true;
01192 break;
01193 }
01194 }
01195
01196 if ( graphicChildElem.localName() == "ExternalGraphic" || graphicChildElem.localName() == "Mark" )
01197 {
01198
01199 QDomElement formatElem = graphicChildElem.firstChildElement( "Format" );
01200 if ( formatElem.isNull() )
01201 continue;
01202
01203 format = formatElem.firstChild().nodeValue();
01204
01205
01206
01207 if ( graphicChildElem.localName() == "ExternalGraphic" && format != "image/svg+xml" )
01208 continue;
01209
01210
01211
01212 if ( graphicChildElem.localName() == "Mark" && format != "ttf" )
01213 continue;
01214
01215
01216 QDomElement onlineResourceElem = graphicChildElem.firstChildElement( "OnlineResource" );
01217 QDomElement inlineContentElem = graphicChildElem.firstChildElement( "InlineContent" );
01218
01219 if ( !onlineResourceElem.isNull() )
01220 {
01221 name = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
01222
01223 if ( graphicChildElem.localName() == "Mark" && format == "ttf" )
01224 {
01225
01226 if ( name.startsWith( "ttf://" ) )
01227 name = name.mid( 6 );
01228
01229
01230 QDomElement markIndexElem = graphicChildElem.firstChildElement( "MarkIndex" );
01231 if ( markIndexElem.isNull() )
01232 continue;
01233
01234 bool ok;
01235 int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
01236 if ( !ok || v < 0 )
01237 continue;
01238
01239 markIndex = v;
01240 }
01241
01242 found = true;
01243 break;
01244 }
01245 else if ( !inlineContentElem.isNull() )
01246 continue;
01247 else
01248 continue;
01249 }
01250
01251
01252
01253
01254 if ( graphicChildElem.localName() == "Mark" )
01255 {
01256 name = "square";
01257 found = true;
01258 break;
01259 }
01260 }
01261
01262
01263 if ( found && graphicChildElem.localName() == "Mark" )
01264 {
01265
01266
01267
01268
01269
01270 Qt::BrushStyle markFillStyle;
01271
01272 QDomElement markFillElem = graphicChildElem.firstChildElement( "Fill" );
01273 if ( fillFromSld( markFillElem, markFillStyle, fillColor ) )
01274 validFill = true;
01275
01276
01277
01278 Qt::PenStyle borderStyle;
01279 double borderWidth = 1.0, dashOffset = 0.0;
01280 QVector<qreal> customDashPattern;
01281
01282 QDomElement markStrokeElem = graphicChildElem.firstChildElement( "Stroke" );
01283 if ( lineFromSld( markStrokeElem, borderStyle, borderColor, borderWidth,
01284 0, 0, &customDashPattern, &dashOffset ) )
01285 validBorder = true;
01286 }
01287
01288 if ( found )
01289 {
01290
01291 QDomElement opacityElem = graphicElem.firstChildElement( "Opacity" );
01292 if ( !opacityElem.isNull() )
01293 fillColor.setAlpha( decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
01294
01295 QDomElement sizeElem = graphicElem.firstChildElement( "Size" );
01296 if ( !sizeElem.isNull() )
01297 {
01298 bool ok;
01299 double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
01300 if ( ok && v > 0 )
01301 size = v;
01302 }
01303
01304 QString angleFunc;
01305 if ( rotationFromSldElement( graphicElem, angleFunc ) && !angleFunc.isEmpty() )
01306 {
01307 bool ok;
01308 double v = angleFunc.toDouble( &ok );
01309 if ( ok )
01310 angle = v;
01311 }
01312
01313 displacementFromSldElement( graphicElem, offset );
01314 }
01315 }
01316 }
01317
01318 if ( validFill || validBorder )
01319 {
01320 if ( format == "image/svg+xml" )
01321 {
01322 QgsStringMap map;
01323 map["name"] = name;
01324 map["fill"] = fillColor.name();
01325 map["outline"] = borderColor.name();
01326 map["outline-width"] = QString::number( borderWidth );
01327 if ( size > 0 )
01328 map["size"] = QString::number( size );
01329 if ( !doubleNear( angle, 0.0 ) )
01330 map["angle"] = QString::number( angle );
01331 if ( !offset.isNull() )
01332 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( offset );
01333 layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SvgMarker", map ) );
01334 }
01335 else if ( format == "ttf" )
01336 {
01337 QgsStringMap map;
01338 map["font"] = name;
01339 map["chr"] = markIndex;
01340 map["color"] = QgsSymbolLayerV2Utils::encodeColor( validFill ? fillColor : Qt::transparent );
01341 if ( size > 0 )
01342 map["size"] = QString::number( size );
01343 if ( !doubleNear( angle, 0.0 ) )
01344 map["angle"] = QString::number( angle );
01345 if ( !offset.isNull() )
01346 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( offset );
01347 layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "FontMarker", map ) );
01348 }
01349 }
01350 }
01351
01352 if ( layers.isEmpty() )
01353 return false;
01354
01355 layerList << layers;
01356 layers.clear();
01357 return true;
01358 }
01359
01360 void QgsSymbolLayerV2Utils::fillToSld( QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color )
01361 {
01362 QString patternName;
01363 switch ( brushStyle )
01364 {
01365 case Qt::NoBrush:
01366 return;
01367
01368 case Qt::SolidPattern:
01369 if ( color.isValid() )
01370 {
01371 element.appendChild( createSvgParameterElement( doc, "fill", color.name() ) );
01372 if ( color.alpha() < 255 )
01373 element.appendChild( createSvgParameterElement( doc, "fill-opacity", encodeSldAlpha( color.alpha() ) ) );
01374 }
01375 return;
01376
01377 case Qt::CrossPattern:
01378 case Qt::DiagCrossPattern:
01379 case Qt::HorPattern:
01380 case Qt::VerPattern:
01381 case Qt::BDiagPattern:
01382 case Qt::FDiagPattern:
01383 case Qt::Dense1Pattern:
01384 case Qt::Dense2Pattern:
01385 case Qt::Dense3Pattern:
01386 case Qt::Dense4Pattern:
01387 case Qt::Dense5Pattern:
01388 case Qt::Dense6Pattern:
01389 case Qt::Dense7Pattern:
01390 patternName = encodeSldBrushStyle( brushStyle );
01391 break;
01392
01393 default:
01394 element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
01395 return;
01396 }
01397
01398 QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
01399 element.appendChild( graphicFillElem );
01400
01401 QDomElement graphicElem = doc.createElement( "se:Graphic" );
01402 graphicFillElem.appendChild( graphicElem );
01403
01404 QColor fillColor = patternName.startsWith( "brush://" ) ? color : QColor();
01405 QColor borderColor = !patternName.startsWith( "brush://" ) ? color : QColor();
01406
01407
01408 wellKnownMarkerToSld( doc, graphicFillElem, patternName, fillColor, borderColor );
01409 }
01410
01411 bool QgsSymbolLayerV2Utils::fillFromSld( QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color )
01412 {
01413 QgsDebugMsg( "Entered." );
01414
01415 brushStyle = Qt::SolidPattern;
01416 color = QColor( "#808080" );
01417
01418 if ( element.isNull() )
01419 {
01420 brushStyle = Qt::NoBrush;
01421 color = QColor();
01422 return true;
01423 }
01424
01425 QDomElement graphicFillElem = element.firstChildElement( "GraphicFill" );
01426
01427 if ( graphicFillElem.isNull() )
01428 {
01429 QgsStringMap svgParams = getSvgParameterList( element );
01430 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
01431 {
01432 QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
01433
01434 if ( it.key() == "fill" )
01435 color = QColor( it.value() );
01436 else if ( it.key() == "fill-opacity" )
01437 color.setAlpha( decodeSldAlpha( it.value() ) );
01438 }
01439 }
01440 else
01441 {
01442 QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
01443 if ( graphicElem.isNull() )
01444 return false;
01445
01446 QString patternName = "square";
01447 QColor fillColor, borderColor;
01448 double borderWidth, size;
01449 if ( !wellKnownMarkerFromSld( graphicFillElem, patternName, fillColor, borderColor, borderWidth, size ) )
01450 return false;
01451
01452 brushStyle = decodeSldBrushStyle( patternName );
01453 if ( brushStyle == Qt::NoBrush )
01454 return false;
01455
01456 QColor c = patternName.startsWith( "brush://" ) ? fillColor : borderColor;
01457 if ( c.isValid() )
01458 color = c;
01459 }
01460
01461 return true;
01462 }
01463
01464 void QgsSymbolLayerV2Utils::lineToSld( QDomDocument &doc, QDomElement &element,
01465 Qt::PenStyle penStyle, QColor color, double width,
01466 const Qt::PenJoinStyle *penJoinStyle, const Qt::PenCapStyle *penCapStyle,
01467 const QVector<qreal> *customDashPattern, double dashOffset )
01468 {
01469 QVector<qreal> dashPattern;
01470 if ( penStyle == Qt::CustomDashLine && !customDashPattern )
01471 {
01472 element.appendChild( doc.createComment( "WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) );
01473 penStyle = Qt::DashLine;
01474 customDashPattern = &dashPattern;
01475 }
01476
01477 switch ( penStyle )
01478 {
01479 case Qt::NoPen:
01480 return;
01481
01482 case Qt::SolidLine:
01483 break;
01484
01485 case Qt::DashLine:
01486 dashPattern.push_back( 4.0 );
01487 dashPattern.push_back( 2.0 );
01488 break;
01489 case Qt::DotLine:
01490 dashPattern.push_back( 1.0 );
01491 dashPattern.push_back( 2.0 );
01492 break;
01493 case Qt::DashDotLine:
01494 dashPattern.push_back( 4.0 );
01495 dashPattern.push_back( 2.0 );
01496 dashPattern.push_back( 1.0 );
01497 dashPattern.push_back( 2.0 );
01498 break;
01499 case Qt::DashDotDotLine:
01500 dashPattern.push_back( 4.0 );
01501 dashPattern.push_back( 2.0 );
01502 dashPattern.push_back( 1.0 );
01503 dashPattern.push_back( 2.0 );
01504 dashPattern.push_back( 1.0 );
01505 dashPattern.push_back( 2.0 );
01506 break;
01507
01508 case Qt::CustomDashLine:
01509 Q_ASSERT( customDashPattern );
01510 break;
01511
01512 default:
01513 element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
01514 return;
01515 }
01516
01517 if ( color.isValid() )
01518 {
01519 element.appendChild( createSvgParameterElement( doc, "stroke", color.name() ) );
01520 if ( color.alpha() < 255 )
01521 element.appendChild( createSvgParameterElement( doc, "stroke-opacity", encodeSldAlpha( color.alpha() ) ) );
01522 }
01523 if ( width > 0 )
01524 element.appendChild( createSvgParameterElement( doc, "stroke-width", QString::number( width ) ) );
01525 if ( penJoinStyle )
01526 element.appendChild( createSvgParameterElement( doc, "stroke-linejoin", encodeSldLineJoinStyle( *penJoinStyle ) ) );
01527 if ( penCapStyle )
01528 element.appendChild( createSvgParameterElement( doc, "stroke-linecap", encodeSldLineCapStyle( *penCapStyle ) ) );
01529
01530 if ( customDashPattern && customDashPattern->size() > 0 )
01531 {
01532 element.appendChild( createSvgParameterElement( doc, "stroke-dasharray", encodeSldRealVector( *customDashPattern ) ) );
01533 if ( !doubleNear( dashOffset, 0.0 ) )
01534 element.appendChild( createSvgParameterElement( doc, "stroke-dashoffset", QString::number( dashOffset ) ) );
01535 }
01536 }
01537
01538
01539 bool QgsSymbolLayerV2Utils::lineFromSld( QDomElement &element,
01540 Qt::PenStyle &penStyle, QColor &color, double &width,
01541 Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
01542 QVector<qreal> *customDashPattern, double *dashOffset )
01543 {
01544 QgsDebugMsg( "Entered." );
01545
01546 penStyle = Qt::SolidLine;
01547 color = QColor( "#000000" );
01548 width = 1;
01549 if ( penJoinStyle )
01550 *penJoinStyle = Qt::BevelJoin;
01551 if ( penCapStyle )
01552 *penCapStyle = Qt::SquareCap;
01553 if ( customDashPattern )
01554 customDashPattern->clear();
01555 if ( dashOffset )
01556 *dashOffset = 0;
01557
01558 if ( element.isNull() )
01559 {
01560 penStyle = Qt::NoPen;
01561 color = QColor();
01562 return true;
01563 }
01564
01565 QgsStringMap svgParams = getSvgParameterList( element );
01566 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
01567 {
01568 QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
01569
01570 if ( it.key() == "stroke" )
01571 {
01572 color = QColor( it.value() );
01573 }
01574 else if ( it.key() == "stroke-opacity" )
01575 {
01576 color.setAlpha( decodeSldAlpha( it.value() ) );
01577 }
01578 else if ( it.key() == "stroke-width" )
01579 {
01580 bool ok;
01581 double w = it.value().toDouble( &ok );
01582 if ( ok )
01583 width = w;
01584 }
01585 else if ( it.key() == "stroke-linejoin" && penJoinStyle )
01586 {
01587 *penJoinStyle = decodeSldLineJoinStyle( it.value() );
01588 }
01589 else if ( it.key() == "stroke-linecap" && penCapStyle )
01590 {
01591 *penCapStyle = decodeSldLineCapStyle( it.value() );
01592 }
01593 else if ( it.key() == "stroke-dasharray" && customDashPattern )
01594 {
01595 *customDashPattern = decodeSldRealVector( it.value() );
01596 if ( customDashPattern->size() > 0 )
01597 {
01598
01599
01600 bool dashPatternFound = false;
01601
01602 if ( customDashPattern->count() == 2 )
01603 {
01604 if ( customDashPattern->at( 0 ) == 4.0 &&
01605 customDashPattern->at( 1 ) == 2.0 )
01606 {
01607 penStyle = Qt::DashLine;
01608 dashPatternFound = true;
01609 }
01610 else if ( customDashPattern->at( 0 ) == 1.0 &&
01611 customDashPattern->at( 1 ) == 2.0 )
01612 {
01613 penStyle = Qt::DotLine;
01614 dashPatternFound = true;
01615 }
01616 }
01617 else if ( customDashPattern->count() == 4 )
01618 {
01619 if ( customDashPattern->at( 0 ) == 4.0 &&
01620 customDashPattern->at( 1 ) == 2.0 &&
01621 customDashPattern->at( 2 ) == 1.0 &&
01622 customDashPattern->at( 3 ) == 2.0 )
01623 {
01624 penStyle = Qt::DashDotLine;
01625 dashPatternFound = true;
01626 }
01627 }
01628 else if ( customDashPattern->count() == 6 )
01629 {
01630 if ( customDashPattern->at( 0 ) == 4.0 &&
01631 customDashPattern->at( 1 ) == 2.0 &&
01632 customDashPattern->at( 2 ) == 1.0 &&
01633 customDashPattern->at( 3 ) == 2.0 &&
01634 customDashPattern->at( 4 ) == 1.0 &&
01635 customDashPattern->at( 5 ) == 2.0 )
01636 {
01637 penStyle = Qt::DashDotDotLine;
01638 dashPatternFound = true;
01639 }
01640 }
01641
01642
01643 if ( !dashPatternFound )
01644 {
01645 penStyle = Qt::CustomDashLine;
01646 }
01647 }
01648 }
01649 else if ( it.key() == "stroke-dashoffset" && dashOffset )
01650 {
01651 bool ok;
01652 double d = it.value().toDouble( &ok );
01653 if ( ok )
01654 *dashOffset = d;
01655 }
01656 }
01657
01658 return true;
01659 }
01660
01661 void QgsSymbolLayerV2Utils::externalGraphicToSld( QDomDocument &doc, QDomElement &element,
01662 QString path, QString mime,
01663 QColor color, double size )
01664 {
01665 QDomElement externalGraphicElem = doc.createElement( "se:ExternalGraphic" );
01666 element.appendChild( externalGraphicElem );
01667
01668 createOnlineResourceElement( doc, externalGraphicElem, path, mime );
01669
01670
01671 Q_UNUSED( color );
01672
01673 if ( size >= 0 )
01674 {
01675 QDomElement sizeElem = doc.createElement( "se:Size" );
01676 sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
01677 element.appendChild( sizeElem );
01678 }
01679 }
01680
01681 bool QgsSymbolLayerV2Utils::externalGraphicFromSld( QDomElement &element,
01682 QString &path, QString &mime,
01683 QColor &color, double &size )
01684 {
01685 QgsDebugMsg( "Entered." );
01686 Q_UNUSED( color );
01687
01688 QDomElement externalGraphicElem = element.firstChildElement( "ExternalGraphic" );
01689 if ( externalGraphicElem.isNull() )
01690 return false;
01691
01692 onlineResourceFromSldElement( externalGraphicElem, path, mime );
01693
01694 QDomElement sizeElem = element.firstChildElement( "Size" );
01695 if ( !sizeElem.isNull() )
01696 {
01697 bool ok;
01698 double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
01699 if ( ok )
01700 size = s;
01701 }
01702
01703 return true;
01704 }
01705
01706 void QgsSymbolLayerV2Utils::externalMarkerToSld( QDomDocument &doc, QDomElement &element,
01707 QString path, QString format, int *markIndex,
01708 QColor color, double size )
01709 {
01710 QDomElement markElem = doc.createElement( "se:Mark" );
01711 element.appendChild( markElem );
01712
01713 createOnlineResourceElement( doc, markElem, path, format );
01714
01715 if ( markIndex )
01716 {
01717 QDomElement markIndexElem = doc.createElement( "se:MarkIndex" );
01718 markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
01719 markElem.appendChild( markIndexElem );
01720 }
01721
01722
01723 QDomElement fillElem = doc.createElement( "se:Fill" );
01724 fillToSld( doc, fillElem, Qt::SolidPattern, color );
01725 markElem.appendChild( fillElem );
01726
01727
01728 if ( !doubleNear( size, 0.0 ) && size > 0 )
01729 {
01730 QDomElement sizeElem = doc.createElement( "se:Size" );
01731 sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
01732 element.appendChild( sizeElem );
01733 }
01734 }
01735
01736 bool QgsSymbolLayerV2Utils::externalMarkerFromSld( QDomElement &element,
01737 QString &path, QString &format, int &markIndex,
01738 QColor &color, double &size )
01739 {
01740 QgsDebugMsg( "Entered." );
01741
01742 color = QColor();
01743 markIndex = -1;
01744 size = -1;
01745
01746 QDomElement markElem = element.firstChildElement( "Mark" );
01747 if ( markElem.isNull() )
01748 return false;
01749
01750 onlineResourceFromSldElement( markElem, path, format );
01751
01752 QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
01753 if ( !markIndexElem.isNull() )
01754 {
01755 bool ok;
01756 int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
01757 if ( ok )
01758 markIndex = i;
01759 }
01760
01761
01762 QDomElement fillElem = markElem.firstChildElement( "Fill" );
01763 Qt::BrushStyle b = Qt::SolidPattern;
01764 fillFromSld( fillElem, b, color );
01765
01766
01767
01768 QDomElement sizeElem = element.firstChildElement( "Size" );
01769 if ( !sizeElem.isNull() )
01770 {
01771 bool ok;
01772 double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
01773 if ( ok )
01774 size = s;
01775 }
01776
01777 return true;
01778 }
01779
01780 void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
01781 QString name, QColor color, QColor borderColor,
01782 double borderWidth, double size )
01783 {
01784 QDomElement markElem = doc.createElement( "se:Mark" );
01785 element.appendChild( markElem );
01786
01787 QDomElement wellKnownNameElem = doc.createElement( "se:WellKnownName" );
01788 wellKnownNameElem.appendChild( doc.createTextNode( name ) );
01789 markElem.appendChild( wellKnownNameElem );
01790
01791
01792 if ( color.isValid() )
01793 {
01794 QDomElement fillElem = doc.createElement( "se:Fill" );
01795 fillToSld( doc, fillElem, Qt::SolidPattern, color );
01796 markElem.appendChild( fillElem );
01797 }
01798
01799
01800 if ( borderColor.isValid() )
01801 {
01802 QDomElement strokeElem = doc.createElement( "se:Stroke" );
01803 lineToSld( doc, strokeElem, Qt::SolidLine, borderColor, borderWidth );
01804 markElem.appendChild( strokeElem );
01805 }
01806
01807
01808 if ( !doubleNear( size, 0.0 ) && size > 0 )
01809 {
01810 QDomElement sizeElem = doc.createElement( "se:Size" );
01811 sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
01812 element.appendChild( sizeElem );
01813 }
01814 }
01815
01816 bool QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( QDomElement &element,
01817 QString &name, QColor &color, QColor &borderColor,
01818 double &borderWidth, double &size )
01819 {
01820 QgsDebugMsg( "Entered." );
01821
01822 name = "square";
01823 color = QColor();
01824 borderColor = QColor( "#000000" );
01825 borderWidth = 1;
01826 size = 6;
01827
01828 QDomElement markElem = element.firstChildElement( "Mark" );
01829 if ( markElem.isNull() )
01830 return false;
01831
01832 QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
01833 if ( !wellKnownNameElem.isNull() )
01834 {
01835 name = wellKnownNameElem.firstChild().nodeValue();
01836 QgsDebugMsg( "found Mark with well known name: " + name );
01837 }
01838
01839
01840 QDomElement fillElem = markElem.firstChildElement( "Fill" );
01841 Qt::BrushStyle b = Qt::SolidPattern;
01842 fillFromSld( fillElem, b, color );
01843
01844
01845
01846 QDomElement strokeElem = markElem.firstChildElement( "Stroke" );
01847 Qt::PenStyle p = Qt::SolidLine;
01848 lineFromSld( strokeElem, p, borderColor, borderWidth );
01849
01850
01851
01852 QDomElement sizeElem = element.firstChildElement( "Size" );
01853 if ( !sizeElem.isNull() )
01854 {
01855 bool ok;
01856 double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
01857 if ( ok )
01858 size = s;
01859 }
01860
01861 return true;
01862 }
01863
01864 void QgsSymbolLayerV2Utils::createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc )
01865 {
01866 if ( !rotationFunc.isEmpty() )
01867 {
01868 QDomElement rotationElem = doc.createElement( "se:Rotation" );
01869 createFunctionElement( doc, rotationElem, rotationFunc );
01870 element.appendChild( rotationElem );
01871 }
01872 }
01873
01874 bool QgsSymbolLayerV2Utils::rotationFromSldElement( QDomElement &element, QString &rotationFunc )
01875 {
01876 QDomElement rotationElem = element.firstChildElement( "Rotation" );
01877 if ( !rotationElem.isNull() )
01878 {
01879 functionFromSldElement( rotationElem, rotationFunc );
01880 }
01881 return true;
01882 }
01883
01884
01885 void QgsSymbolLayerV2Utils::createOpacityElement( QDomDocument &doc, QDomElement &element, QString alphaFunc )
01886 {
01887 if ( !alphaFunc.isEmpty() )
01888 {
01889 QDomElement opacityElem = doc.createElement( "se:Opacity" );
01890 createFunctionElement( doc, opacityElem, alphaFunc );
01891 element.appendChild( opacityElem );
01892 }
01893 }
01894
01895 bool QgsSymbolLayerV2Utils::opacityFromSldElement( QDomElement &element, QString &alphaFunc )
01896 {
01897 QDomElement opacityElem = element.firstChildElement( "Opacity" );
01898 if ( !opacityElem.isNull() )
01899 {
01900 functionFromSldElement( opacityElem, alphaFunc );
01901 }
01902 return true;
01903 }
01904
01905 void QgsSymbolLayerV2Utils::createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset )
01906 {
01907 if ( offset.isNull() )
01908 return;
01909
01910 QDomElement displacementElem = doc.createElement( "se:Displacement" );
01911 element.appendChild( displacementElem );
01912
01913 QDomElement dispXElem = doc.createElement( "se:DisplacementX" );
01914 dispXElem.appendChild( doc.createTextNode( QString::number( offset.x() ) ) );
01915
01916 QDomElement dispYElem = doc.createElement( "se:DisplacementY" );
01917 dispYElem.appendChild( doc.createTextNode( QString::number( offset.y() ) ) );
01918
01919 displacementElem.appendChild( dispXElem );
01920 displacementElem.appendChild( dispYElem );
01921 }
01922
01923 bool QgsSymbolLayerV2Utils::displacementFromSldElement( QDomElement &element, QPointF &offset )
01924 {
01925 offset = QPointF( 0, 0 );
01926
01927 QDomElement displacementElem = element.firstChildElement( "Displacement" );
01928 if ( displacementElem.isNull() )
01929 return true;
01930
01931 QDomElement dispXElem = element.firstChildElement( "DisplacementX" );
01932 if ( !dispXElem.isNull() )
01933 {
01934 bool ok;
01935 double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
01936 if ( ok )
01937 offset.setX( offsetX );
01938 }
01939
01940 QDomElement dispYElem = element.firstChildElement( "DisplacementY" );
01941 if ( !dispYElem.isNull() )
01942 {
01943 bool ok;
01944 double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
01945 if ( ok )
01946 offset.setY( offsetY );
01947 }
01948
01949 return true;
01950 }
01951
01952 void QgsSymbolLayerV2Utils::labelTextToSld( QDomDocument &doc, QDomElement &element,
01953 QString label, QFont font,
01954 QColor color, double size )
01955 {
01956 QDomElement labelElem = doc.createElement( "se:Label" );
01957 labelElem.appendChild( doc.createTextNode( label ) );
01958 element.appendChild( labelElem );
01959
01960 QDomElement fontElem = doc.createElement( "se:Font" );
01961 element.appendChild( fontElem );
01962
01963 fontElem.appendChild( createSvgParameterElement( doc, "font-family", font.family() ) );
01964 #if 0
01965 fontElem.appendChild( createSldParameterElement( doc, "font-style", encodeSldFontStyle( font.style() ) ) );
01966 fontElem.appendChild( createSldParameterElement( doc, "font-weight", encodeSldFontWeight( font.weight() ) ) );
01967 #endif
01968 fontElem.appendChild( createSvgParameterElement( doc, "font-size", QString::number( size ) ) );
01969
01970
01971 if ( color.isValid() )
01972 {
01973 QDomElement fillElem = doc.createElement( "Fill" );
01974 fillToSld( doc, fillElem, Qt::SolidPattern, color );
01975 element.appendChild( fillElem );
01976 }
01977 }
01978
01979 void QgsSymbolLayerV2Utils::createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc )
01980 {
01981 if ( geomFunc.isEmpty() )
01982 return;
01983
01984 QDomElement geometryElem = doc.createElement( "Geometry" );
01985 element.appendChild( geometryElem );
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010 createFunctionElement( doc, geometryElem, geomFunc );
02011 }
02012
02013 bool QgsSymbolLayerV2Utils::geometryFromSldElement( QDomElement &element, QString &geomFunc )
02014 {
02015 QDomElement geometryElem = element.firstChildElement( "Geometry" );
02016 if ( geometryElem.isNull() )
02017 return true;
02018
02019 return functionFromSldElement( geometryElem, geomFunc );
02020 }
02021
02022 bool QgsSymbolLayerV2Utils::createFunctionElement( QDomDocument &doc, QDomElement &element, QString function )
02023 {
02024
02025 QgsExpression expr( function );
02026 if ( expr.hasParserError() )
02027 {
02028 element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function ) );
02029 return false;
02030 }
02031 expr.toOgcFilter( doc, element );
02032 return true;
02033 }
02034
02035 bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QString &function )
02036 {
02037 QgsDebugMsg( "Entered." );
02038
02039 QgsExpression *expr = QgsExpression::createFromOgcFilter( element );
02040 if ( !expr )
02041 return false;
02042
02043 bool valid = expr->hasParserError();
02044 if ( !valid )
02045 {
02046 QgsDebugMsg( "parser error: " + expr->parserErrorString() );
02047 }
02048 else
02049 {
02050 function = expr->dump();
02051 }
02052
02053 delete expr;
02054 return valid;
02055 }
02056
02057 void QgsSymbolLayerV2Utils::createOnlineResourceElement( QDomDocument &doc, QDomElement &element,
02058 QString path, QString format )
02059 {
02060 QDomElement onlineResourceElem = doc.createElement( "OnlineResource" );
02061 onlineResourceElem.setAttribute( "xlink:type", "simple" );
02062 onlineResourceElem.setAttribute( "xlink:href", path );
02063 element.appendChild( onlineResourceElem );
02064
02065 QDomElement formatElem = doc.createElement( "Format" );
02066 formatElem.appendChild( doc.createTextNode( format ) );
02067 element.appendChild( formatElem );
02068 }
02069
02070 bool QgsSymbolLayerV2Utils::onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format )
02071 {
02072 QgsDebugMsg( "Entered." );
02073
02074 QDomElement onlineResourceElem = element.firstChildElement( "OnlineResource" );
02075 if ( onlineResourceElem.isNull() )
02076 return false;
02077
02078 path = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
02079
02080 QDomElement formatElem = element.firstChildElement( "Format" );
02081 if ( formatElem.isNull() )
02082 return false;
02083
02084 format = formatElem.firstChild().nodeValue();
02085 return true;
02086 }
02087
02088
02089 QDomElement QgsSymbolLayerV2Utils::createSvgParameterElement( QDomDocument &doc, QString name, QString value )
02090 {
02091 QDomElement nodeElem = doc.createElement( "se:SvgParameter" );
02092 nodeElem.setAttribute( "name", name );
02093 nodeElem.appendChild( doc.createTextNode( value ) );
02094 return nodeElem;
02095 }
02096
02097 QgsStringMap QgsSymbolLayerV2Utils::getSvgParameterList( QDomElement &element )
02098 {
02099 QgsStringMap params;
02100
02101 QDomElement paramElem = element.firstChildElement();
02102 while ( !paramElem.isNull() )
02103 {
02104 if ( paramElem.localName() == "SvgParameter" || paramElem.localName() == "CssParameter" )
02105 {
02106 QString name = paramElem.attribute( "name" );
02107 QString value = paramElem.firstChild().nodeValue();
02108
02109 if ( !name.isEmpty() && !value.isEmpty() )
02110 params[ name ] = value;
02111 }
02112
02113 paramElem = paramElem.nextSiblingElement();
02114 }
02115
02116 return params;
02117 }
02118
02119 QDomElement QgsSymbolLayerV2Utils::createVendorOptionElement( QDomDocument &doc, QString name, QString value )
02120 {
02121 QDomElement nodeElem = doc.createElement( "VendorOption" );
02122 nodeElem.setAttribute( "name", name );
02123 nodeElem.appendChild( doc.createTextNode( value ) );
02124 return nodeElem;
02125 }
02126
02127 QgsStringMap QgsSymbolLayerV2Utils::getVendorOptionList( QDomElement &element )
02128 {
02129 QgsStringMap params;
02130
02131 QDomElement paramElem = element.firstChildElement( "VendorOption" );
02132 while ( !paramElem.isNull() )
02133 {
02134 QString name = paramElem.attribute( "name" );
02135 QString value = paramElem.firstChild().nodeValue();
02136
02137 if ( !name.isEmpty() && !value.isEmpty() )
02138 params[ name ] = value;
02139
02140 paramElem = paramElem.nextSiblingElement( "VendorOption" );
02141 }
02142
02143 return params;
02144 }
02145
02146
02147 QgsStringMap QgsSymbolLayerV2Utils::parseProperties( QDomElement& element )
02148 {
02149 QgsStringMap props;
02150 QDomElement e = element.firstChildElement();
02151 while ( !e.isNull() )
02152 {
02153 if ( e.tagName() != "prop" )
02154 {
02155 QgsDebugMsg( "unknown tag " + e.tagName() );
02156 }
02157 else
02158 {
02159 QString propKey = e.attribute( "k" );
02160 QString propValue = e.attribute( "v" );
02161 props[propKey] = propValue;
02162 }
02163 e = e.nextSiblingElement();
02164 }
02165 return props;
02166 }
02167
02168
02169 void QgsSymbolLayerV2Utils::saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element )
02170 {
02171 for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
02172 {
02173 QDomElement propEl = doc.createElement( "prop" );
02174 propEl.setAttribute( "k", it.key() );
02175 propEl.setAttribute( "v", it.value() );
02176 element.appendChild( propEl );
02177 }
02178 }
02179
02180 QgsSymbolV2Map QgsSymbolLayerV2Utils::loadSymbols( QDomElement& element )
02181 {
02182
02183
02184 QgsSymbolV2Map symbols;
02185 QDomElement e = element.firstChildElement();
02186
02187 while ( !e.isNull() )
02188 {
02189 if ( e.tagName() == "symbol" )
02190 {
02191 QgsSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol( e );
02192 if ( symbol != NULL )
02193 symbols.insert( e.attribute( "name" ), symbol );
02194 }
02195 else
02196 {
02197 QgsDebugMsg( "unknown tag: " + e.tagName() );
02198 }
02199 e = e.nextSiblingElement();
02200 }
02201
02202
02203
02204
02205
02206 QStringList subsymbols;
02207
02208 for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
02209 {
02210 if ( it.key()[0] != '@' )
02211 continue;
02212
02213
02214 subsymbols.append( it.key() );
02215
02216 QStringList parts = it.key().split( "@" );
02217 if ( parts.count() < 3 )
02218 {
02219 QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
02220 delete it.value();
02221 continue;
02222 }
02223 QString symname = parts[1];
02224 int symlayer = parts[2].toInt();
02225
02226 if ( !symbols.contains( symname ) )
02227 {
02228 QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
02229 delete it.value();
02230 continue;
02231 }
02232
02233 QgsSymbolV2* sym = symbols[symname];
02234 if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
02235 {
02236 QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
02237 delete it.value();
02238 continue;
02239 }
02240
02241
02242 bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
02243 if ( !res )
02244 {
02245 QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
02246 }
02247
02248
02249 }
02250
02251
02252 for ( int i = 0; i < subsymbols.count(); i++ )
02253 symbols.take( subsymbols[i] );
02254
02255 return symbols;
02256 }
02257
02258 QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString tagName, QDomDocument& doc )
02259 {
02260 QDomElement symbolsElem = doc.createElement( tagName );
02261
02262 QMap<QString, QgsSymbolV2*> subSymbols;
02263
02264
02265 for ( QMap<QString, QgsSymbolV2*>::iterator its = symbols.begin(); its != symbols.end(); ++its )
02266 {
02267 QDomElement symEl = saveSymbol( its.key(), its.value(), doc, &subSymbols );
02268 symbolsElem.appendChild( symEl );
02269 }
02270
02271
02272 for ( QMap<QString, QgsSymbolV2*>::iterator itsub = subSymbols.begin(); itsub != subSymbols.end(); ++itsub )
02273 {
02274 QDomElement subsymEl = saveSymbol( itsub.key(), itsub.value(), doc );
02275 symbolsElem.appendChild( subsymEl );
02276 }
02277
02278 return symbolsElem;
02279 }
02280
02281 void QgsSymbolLayerV2Utils::clearSymbolMap( QgsSymbolV2Map& symbols )
02282 {
02283 foreach( QString name, symbols.keys() )
02284 {
02285 delete symbols.value( name );
02286 }
02287 symbols.clear();
02288 }
02289
02290
02291 QgsVectorColorRampV2* QgsSymbolLayerV2Utils::loadColorRamp( QDomElement& element )
02292 {
02293 QString rampType = element.attribute( "type" );
02294
02295
02296 QgsStringMap props = QgsSymbolLayerV2Utils::parseProperties( element );
02297
02298 if ( rampType == "gradient" )
02299 return QgsVectorGradientColorRampV2::create( props );
02300 else if ( rampType == "random" )
02301 return QgsVectorRandomColorRampV2::create( props );
02302 else if ( rampType == "colorbrewer" )
02303 return QgsVectorColorBrewerColorRampV2::create( props );
02304 else
02305 {
02306 QgsDebugMsg( "unknown colorramp type " + rampType );
02307 return NULL;
02308 }
02309 }
02310
02311
02312 QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc )
02313 {
02314 QDomElement rampEl = doc.createElement( "colorramp" );
02315 rampEl.setAttribute( "type", ramp->type() );
02316 rampEl.setAttribute( "name", name );
02317
02318 QgsSymbolLayerV2Utils::saveProperties( ramp->properties(), doc, rampEl );
02319 return rampEl;
02320 }
02321
02322 double QgsSymbolLayerV2Utils::lineWidthScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
02323 {
02324
02325 if ( u == QgsSymbolV2::MM )
02326 {
02327 return c.scaleFactor();
02328 }
02329 else
02330 {
02331 double mup = c.mapToPixel().mapUnitsPerPixel();
02332 if ( mup > 0 )
02333 {
02334 return 1.0 / mup;
02335 }
02336 else
02337 {
02338 return 1.0;
02339 }
02340 }
02341 }
02342
02343 double QgsSymbolLayerV2Utils::pixelSizeScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
02344 {
02345 if ( u == QgsSymbolV2::MM )
02346 {
02347 return ( c.scaleFactor() * c.rasterScaleFactor() );
02348 }
02349 else
02350 {
02351 double mup = c.mapToPixel().mapUnitsPerPixel();
02352 if ( mup > 0 )
02353 {
02354 return c.rasterScaleFactor() / c.mapToPixel().mapUnitsPerPixel();
02355 }
02356 else
02357 {
02358 return 1.0;
02359 }
02360 }
02361 }
02362
02363 QgsRenderContext QgsSymbolLayerV2Utils::createRenderContext( QPainter* p )
02364 {
02365 QgsRenderContext context;
02366 context.setPainter( p );
02367 context.setRasterScaleFactor( 1.0 );
02368 if ( p && p->device() )
02369 {
02370 context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
02371 }
02372 else
02373 {
02374 context.setScaleFactor( 3.465 );
02375 }
02376 return context;
02377 }
02378
02379 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
02380 {
02381 if ( !image )
02382 {
02383 return;
02384 }
02385
02386 QRgb myRgb;
02387 QImage::Format format = image->format();
02388 if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
02389 {
02390 QgsDebugMsg( "no alpha channel." );
02391 return;
02392 }
02393
02394
02395 for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
02396 {
02397 QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
02398 for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
02399 {
02400 myRgb = scanLine[widthIndex];
02401 if ( format == QImage::Format_ARGB32_Premultiplied )
02402 scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
02403 else
02404 scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
02405 }
02406 }
02407 }
02408
02409 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
02410 {
02411 switch ( lhs.type() )
02412 {
02413 case QVariant::Int:
02414 return lhs.toInt() < rhs.toInt();
02415 case QVariant::UInt:
02416 return lhs.toUInt() < rhs.toUInt();
02417 case QVariant::LongLong:
02418 return lhs.toLongLong() < rhs.toLongLong();
02419 case QVariant::ULongLong:
02420 return lhs.toULongLong() < rhs.toULongLong();
02421 case QVariant::Double:
02422 return lhs.toDouble() < rhs.toDouble();
02423 case QVariant::Char:
02424 return lhs.toChar() < rhs.toChar();
02425 case QVariant::Date:
02426 return lhs.toDate() < rhs.toDate();
02427 case QVariant::Time:
02428 return lhs.toTime() < rhs.toTime();
02429 case QVariant::DateTime:
02430 return lhs.toDateTime() < rhs.toDateTime();
02431 default:
02432 return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
02433 }
02434 }
02435
02436 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
02437 {
02438 return ! _QVariantLessThan( lhs, rhs );
02439 }
02440
02441 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
02442 {
02443 if ( order == Qt::AscendingOrder )
02444 {
02445 qSort( list.begin(), list.end(), _QVariantLessThan );
02446 }
02447 else
02448 {
02449 qSort( list.begin(), list.end(), _QVariantGreaterThan );
02450 }
02451 }
02452
02453 QPointF QgsSymbolLayerV2Utils::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance )
02454 {
02455 double dx = directionPoint.x() - startPoint.x();
02456 double dy = directionPoint.y() - startPoint.y();
02457 double length = sqrt( dx * dx + dy * dy );
02458 double scaleFactor = distance / length;
02459 return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
02460 }