Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgssymbollayerv2utils.cpp
Go to the documentation of this file.
00001 
00002 #include "qgssymbollayerv2utils.h"
00003 
00004 #include "qgssymbollayerv2.h"
00005 #include "qgssymbollayerv2registry.h"
00006 #include "qgssymbolv2.h"
00007 #include "qgsvectorcolorrampv2.h"
00008 
00009 #include "qgslogger.h"
00010 #include "qgsrendercontext.h"
00011 
00012 #include <QColor>
00013 #include <QDomNode>
00014 #include <QDomElement>
00015 #include <QIcon>
00016 #include <QPainter>
00017 
00018 QString QgsSymbolLayerV2Utils::encodeColor( QColor color )
00019 {
00020   return QString( "%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
00021 }
00022 
00023 QColor QgsSymbolLayerV2Utils::decodeColor( QString str )
00024 {
00025   QStringList lst = str.split( "," );
00026   if ( lst.count() < 3 )
00027   {
00028     return QColor();
00029   }
00030   int red, green, blue, alpha;
00031   red = lst[0].toInt();
00032   green = lst[1].toInt();
00033   blue = lst[2].toInt();
00034   alpha = 255;
00035   if ( lst.count() > 3 )
00036   {
00037     alpha = lst[3].toInt();
00038   }
00039   return QColor( red, green, blue, alpha );
00040 }
00041 
00042 QString QgsSymbolLayerV2Utils::encodePenStyle( Qt::PenStyle style )
00043 {
00044   switch ( style )
00045   {
00046     case Qt::NoPen:          return "no";
00047     case Qt::SolidLine:      return "solid";
00048     case Qt::DashLine:       return "dash";
00049     case Qt::DotLine:        return "dot";
00050     case Qt::DashDotLine:    return "dash dot";
00051     case Qt::DashDotDotLine: return "dash dot dot";
00052     default: return "???";
00053   }
00054 }
00055 
00056 Qt::PenStyle QgsSymbolLayerV2Utils::decodePenStyle( QString str )
00057 {
00058   if ( str == "no" ) return Qt::NoPen;
00059   if ( str == "solid" ) return Qt::SolidLine;
00060   if ( str == "dash" ) return Qt::DashLine;
00061   if ( str == "dot" ) return Qt::DotLine;
00062   if ( str == "dash dot" ) return Qt::DashDotLine;
00063   if ( str == "dash dot dot" ) return Qt::DashDotDotLine;
00064   return Qt::SolidLine;
00065 }
00066 
00067 QString QgsSymbolLayerV2Utils::encodePenJoinStyle( Qt::PenJoinStyle style )
00068 {
00069   switch ( style )
00070   {
00071     case Qt::BevelJoin: return "bevel";
00072     case Qt::MiterJoin: return "miter";
00073     case Qt::RoundJoin: return "round";
00074     default: return "???";
00075   }
00076 }
00077 
00078 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodePenJoinStyle( QString str )
00079 {
00080   if ( str == "bevel" ) return Qt::BevelJoin;
00081   if ( str == "miter" ) return Qt::MiterJoin;
00082   if ( str == "round" ) return Qt::RoundJoin;
00083   return Qt::BevelJoin;
00084 }
00085 
00086 QString QgsSymbolLayerV2Utils::encodePenCapStyle( Qt::PenCapStyle style )
00087 {
00088   switch ( style )
00089   {
00090     case Qt::SquareCap: return "square";
00091     case Qt::FlatCap:   return "flat";
00092     case Qt::RoundCap:  return "round";
00093     default: return "???";
00094   }
00095 }
00096 
00097 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodePenCapStyle( QString str )
00098 {
00099   if ( str == "square" ) return Qt::SquareCap;
00100   if ( str == "flat" ) return Qt::FlatCap;
00101   if ( str == "round" ) return Qt::RoundCap;
00102   return Qt::SquareCap;
00103 }
00104 
00105 
00106 QString QgsSymbolLayerV2Utils::encodeBrushStyle( Qt::BrushStyle style )
00107 {
00108   switch ( style )
00109   {
00110     case Qt::SolidPattern : return "solid";
00111     case Qt::HorPattern : return "horizontal";
00112     case Qt::VerPattern : return "vertical";
00113     case Qt::CrossPattern : return "cross";
00114     case Qt::BDiagPattern : return "b_diagonal";
00115     case Qt::FDiagPattern : return  "f_diagonal";
00116     case Qt::DiagCrossPattern : return "diagonal_x";
00117     case Qt::Dense1Pattern  : return "dense1";
00118     case Qt::Dense2Pattern  : return "dense2";
00119     case Qt::Dense3Pattern  : return "dense3";
00120     case Qt::Dense4Pattern  : return "dense4";
00121     case Qt::Dense5Pattern  : return "dense5";
00122     case Qt::Dense6Pattern  : return "dense6";
00123     case Qt::Dense7Pattern  : return "dense7";
00124     case Qt::NoBrush : return "no";
00125     default: return "???";
00126   }
00127 }
00128 
00129 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeBrushStyle( QString str )
00130 {
00131   if ( str == "solid" ) return Qt::SolidPattern;
00132   if ( str == "horizontal" ) return Qt::HorPattern;
00133   if ( str == "vertical" ) return Qt::VerPattern;
00134   if ( str == "cross" ) return Qt::CrossPattern;
00135   if ( str == "b_diagonal" ) return Qt::BDiagPattern;
00136   if ( str == "f_diagonal" ) return Qt::FDiagPattern;
00137   if ( str == "diagonal_x" ) return Qt::DiagCrossPattern;
00138   if ( str == "dense1" ) return Qt::Dense1Pattern;
00139   if ( str == "dense2" ) return Qt::Dense2Pattern;
00140   if ( str == "dense3" ) return Qt::Dense3Pattern;
00141   if ( str == "dense4" ) return Qt::Dense4Pattern;
00142   if ( str == "dense5" ) return Qt::Dense5Pattern;
00143   if ( str == "dense6" ) return Qt::Dense6Pattern;
00144   if ( str == "dense7" ) return Qt::Dense7Pattern;
00145   if ( str == "no" ) return Qt::NoBrush;
00146   return Qt::SolidPattern;
00147 }
00148 
00149 QString QgsSymbolLayerV2Utils::encodePoint( QPointF point )
00150 {
00151   return QString( "%1,%2" ).arg( point.x() ).arg( point.y() );
00152 }
00153 
00154 QPointF QgsSymbolLayerV2Utils::decodePoint( QString str )
00155 {
00156   QStringList lst = str.split( ',' );
00157   if ( lst.count() != 2 )
00158     return QPointF( 0, 0 );
00159   return QPointF( lst[0].toDouble(), lst[1].toDouble() );
00160 }
00161 
00162 QString QgsSymbolLayerV2Utils::encodeOutputUnit( QgsSymbolV2::OutputUnit unit )
00163 {
00164   switch ( unit )
00165   {
00166     case QgsSymbolV2::MM:
00167       return "MM";
00168     case QgsSymbolV2::MapUnit:
00169       return "MapUnit";
00170     default:
00171       return "MM";
00172   }
00173 }
00174 
00175 QgsSymbolV2::OutputUnit QgsSymbolLayerV2Utils::decodeOutputUnit( QString str )
00176 {
00177   if ( str == "MM" )
00178   {
00179     return QgsSymbolV2::MM;
00180   }
00181   else if ( str == "MapUnit" )
00182   {
00183     return QgsSymbolV2::MapUnit;
00184   }
00185 
00186   // milimeters are default
00187   return QgsSymbolV2::MM;
00188 }
00189 
00190 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
00191 {
00192   QString vectorString;
00193   QVector<qreal>::const_iterator it = v.constBegin();
00194   for ( ; it != v.constEnd(); ++it )
00195   {
00196     if ( it != v.constBegin() )
00197     {
00198       vectorString.append( ";" );
00199     }
00200     vectorString.append( QString::number( *it ) );
00201   }
00202   return vectorString;
00203 }
00204 
00205 QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
00206 {
00207   QVector<qreal> resultVector;
00208 
00209   QStringList realList = s.split( ";" );
00210   QStringList::const_iterator it = realList.constBegin();
00211   for ( ; it != realList.constEnd(); ++it )
00212   {
00213     resultVector.append( it->toDouble() );
00214   }
00215 
00216   return resultVector;
00217 }
00218 
00219 QIcon QgsSymbolLayerV2Utils::symbolPreviewIcon( QgsSymbolV2* symbol, QSize size )
00220 {
00221   return QIcon( symbolPreviewPixmap( symbol, size ) );
00222 }
00223 
00224 QPixmap QgsSymbolLayerV2Utils::symbolPreviewPixmap( QgsSymbolV2* symbol, QSize size )
00225 {
00226   Q_ASSERT( symbol );
00227 
00228   QPixmap pixmap( size );
00229   pixmap.fill( Qt::transparent );
00230   QPainter painter;
00231   painter.begin( &pixmap );
00232   painter.setRenderHint( QPainter::Antialiasing );
00233   symbol->drawPreviewIcon( &painter, size );
00234   painter.end();
00235   return pixmap;
00236 }
00237 
00238 
00239 QIcon QgsSymbolLayerV2Utils::symbolLayerPreviewIcon( QgsSymbolLayerV2* layer, QgsSymbolV2::OutputUnit u, QSize size )
00240 {
00241   QPixmap pixmap( size );
00242   pixmap.fill( Qt::transparent );
00243   QPainter painter;
00244   painter.begin( &pixmap );
00245   painter.setRenderHint( QPainter::Antialiasing );
00246   QgsRenderContext renderContext = createRenderContext( &painter );
00247   QgsSymbolV2RenderContext symbolContext( renderContext, u );
00248   layer->drawPreviewIcon( symbolContext, size );
00249   painter.end();
00250   return QIcon( pixmap );
00251 }
00252 
00253 QIcon QgsSymbolLayerV2Utils::colorRampPreviewIcon( QgsVectorColorRampV2* ramp, QSize size )
00254 {
00255   return QIcon( colorRampPreviewPixmap( ramp, size ) );
00256 }
00257 
00258 QPixmap QgsSymbolLayerV2Utils::colorRampPreviewPixmap( QgsVectorColorRampV2* ramp, QSize size )
00259 {
00260   QPixmap pixmap( size );
00261   QPainter painter;
00262   painter.begin( &pixmap );
00263   painter.setRenderHint( QPainter::Antialiasing );
00264   painter.eraseRect( QRect( QPoint( 0, 0 ), size ) );
00265   for ( int i = 0; i < size.width(); i++ )
00266   {
00267     QPen pen( ramp->color(( double ) i / size.width() ) );
00268     painter.setPen( pen );
00269     painter.drawLine( i, 0, i, size.height() - 1 );
00270   }
00271   painter.end();
00272   return pixmap;
00273 }
00274 
00275 
00276 #include <QPolygonF>
00277 
00278 #include <cmath>
00279 #include <cfloat>
00280 
00281 
00282 // calculate line's angle and tangent
00283 static bool lineInfo( QPointF p1, QPointF p2, double& angle, double& t )
00284 {
00285   double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();
00286 
00287   if ( x1 == x2 && y1 == y2 )
00288     return false;
00289 
00290   // tangent
00291   t = ( x1 == x2 ? DBL_MAX : ( y2 - y1 ) / ( x2 - x1 ) );
00292 
00293   // angle
00294   if ( t == DBL_MAX )
00295     angle = ( y2 > y1 ? M_PI / 2 : M_PI * 3 / 2 );  // angle is 90 or 270
00296   else if ( t == 0 )
00297     angle = ( x2 > x1 ? 0 : M_PI ); // angle is 0 or 180
00298   else if ( t >= 0 )
00299     angle = ( y2 > y1 ? atan( t ) : M_PI + atan( t ) );
00300   else // t < 0
00301     angle = ( y2 > y1 ? M_PI + atan( t ) : atan( t ) );
00302 
00303   return true;
00304 }
00305 
00306 // offset a point with an angle and distance
00307 static QPointF offsetPoint( QPointF pt, double angle, double dist )
00308 {
00309   return QPointF( pt.x() + dist * cos( angle ), pt.y() + dist * sin( angle ) );
00310 }
00311 
00312 // calc intersection of two (infinite) lines defined by one point and tangent
00313 static QPointF linesIntersection( QPointF p1, double t1, QPointF p2, double t2 )
00314 {
00315   // parallel lines? (or the difference between angles is less than cca 0.1 degree)
00316   if (( t1 == DBL_MAX && t2 == DBL_MAX ) || qAbs( t1 - t2 ) < 0.001 )
00317     return QPointF();
00318 
00319   double x, y;
00320   if ( t1 == DBL_MAX || t2 == DBL_MAX )
00321   {
00322     // in case one line is with angle 90 resp. 270 degrees (tangent undefined)
00323     // swap them so that line 2 is with undefined tangent
00324     if ( t1 == DBL_MAX )
00325     {
00326       QPointF pSwp = p1; p1 = p2; p2 = pSwp;
00327       double  tSwp = t1; t1 = t2; t2 = tSwp;
00328     }
00329 
00330     x = p2.x();
00331   }
00332   else
00333   {
00334     // usual case
00335     x = (( p1.y() - p2.y() ) + t2 * p2.x() - t1 * p1.x() ) / ( t2 - t1 );
00336   }
00337 
00338   y = p1.y() + t1 * ( x - p1.x() );
00339   return QPointF( x, y );
00340 }
00341 
00342 
00343 QPolygonF offsetLine( QPolygonF polyline, double dist )
00344 {
00345   QPolygonF newLine;
00346 
00347   if ( polyline.count() < 2 )
00348     return newLine;
00349 
00350   double angle = 0.0, t_new, t_old = 0;
00351   QPointF pt_old, pt_new;
00352   QPointF p1 = polyline[0], p2;
00353   bool first_point = true;
00354 
00355   for ( int i = 1; i < polyline.count(); i++ )
00356   {
00357     p2 = polyline[i];
00358 
00359     if ( !lineInfo( p1, p2, angle, t_new ) )
00360       continue; // not a line...
00361 
00362     pt_new = offsetPoint( p1, angle + M_PI / 2, dist );
00363 
00364     if ( ! first_point )
00365     {
00366       // if it's not the first line segment
00367       // calc intersection with last line (with offset)
00368       QPointF pt_tmp = linesIntersection( pt_old, t_old, pt_new, t_new );
00369       if ( !pt_tmp.isNull() ) pt_new = pt_tmp;
00370     }
00371 
00372     newLine.append( pt_new );
00373 
00374     pt_old = pt_new;
00375     t_old = t_new;
00376     p1 = p2;
00377     first_point = false;
00378   }
00379 
00380   // last line segment:
00381   pt_new = offsetPoint( p2, angle + M_PI / 2, dist );
00382   newLine.append( pt_new );
00383   return newLine;
00384 }
00385 
00387 
00388 
00389 QgsSymbolV2* QgsSymbolLayerV2Utils::loadSymbol( QDomElement& element )
00390 {
00391   QgsSymbolLayerV2List layers;
00392   QDomNode layerNode = element.firstChild();
00393 
00394   while ( !layerNode.isNull() )
00395   {
00396     QDomElement e = layerNode.toElement();
00397     if ( !e.isNull() )
00398     {
00399       if ( e.tagName() != "layer" )
00400       {
00401         QgsDebugMsg( "unknown tag " + e.tagName() );
00402       }
00403       else
00404       {
00405         QgsSymbolLayerV2* layer = loadSymbolLayer( e );
00406         if ( layer != NULL )
00407           layers.append( layer );
00408       }
00409     }
00410     layerNode = layerNode.nextSibling();
00411   }
00412 
00413   if ( layers.count() == 0 )
00414   {
00415     QgsDebugMsg( "no layers for symbol" );
00416     return NULL;
00417   }
00418 
00419   QString symbolType = element.attribute( "type" );
00420 
00421   QgsSymbolV2* symbol = 0;
00422   if ( symbolType == "line" )
00423     symbol = new QgsLineSymbolV2( layers );
00424   else if ( symbolType == "fill" )
00425     symbol = new QgsFillSymbolV2( layers );
00426   else if ( symbolType == "marker" )
00427     symbol = new QgsMarkerSymbolV2( layers );
00428   else
00429   {
00430     QgsDebugMsg( "unknown symbol type " + symbolType );
00431     return NULL;
00432   }
00433 
00434   symbol->setOutputUnit( decodeOutputUnit( element.attribute( "outputUnit" ) ) );
00435   symbol->setAlpha( element.attribute( "alpha", "1.0" ).toDouble() );
00436 
00437   return symbol;
00438 }
00439 
00440 QgsSymbolLayerV2* QgsSymbolLayerV2Utils::loadSymbolLayer( QDomElement& element )
00441 {
00442   QString layerClass = element.attribute( "class" );
00443   bool locked = element.attribute( "locked" ).toInt();
00444   int pass = element.attribute( "pass" ).toInt();
00445 
00446   // parse properties
00447   QgsStringMap props = parseProperties( element );
00448 
00449   QgsSymbolLayerV2* layer;
00450   layer = QgsSymbolLayerV2Registry::instance()->createSymbolLayer( layerClass, props );
00451   if ( layer )
00452   {
00453     layer->setLocked( locked );
00454     layer->setRenderingPass( pass );
00455     return layer;
00456   }
00457   else
00458   {
00459     QgsDebugMsg( "unknown class " + layerClass );
00460     return NULL;
00461   }
00462 }
00463 
00464 static QString _nameForSymbolType( QgsSymbolV2::SymbolType type )
00465 {
00466   switch ( type )
00467   {
00468     case QgsSymbolV2::Line: return "line";
00469     case QgsSymbolV2::Marker: return "marker";
00470     case QgsSymbolV2::Fill: return "fill";
00471     default: return "";
00472   }
00473 }
00474 
00475 QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc, QgsSymbolV2Map* subSymbols )
00476 {
00477   Q_ASSERT( symbol );
00478 
00479   QDomElement symEl = doc.createElement( "symbol" );
00480   symEl.setAttribute( "type", _nameForSymbolType( symbol->type() ) );
00481   symEl.setAttribute( "name", name );
00482   symEl.setAttribute( "outputUnit", encodeOutputUnit( symbol->outputUnit() ) );
00483   symEl.setAttribute( "alpha", symbol->alpha() );
00484   QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
00485   for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
00486   {
00487     QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
00488 
00489     QDomElement layerEl = doc.createElement( "layer" );
00490     layerEl.setAttribute( "class", layer->layerType() );
00491     layerEl.setAttribute( "locked", layer->isLocked() );
00492     layerEl.setAttribute( "pass", layer->renderingPass() );
00493 
00494     if ( subSymbols != NULL && layer->subSymbol() != NULL )
00495     {
00496       QString subname = QString( "@%1@%2" ).arg( name ).arg( i );
00497       subSymbols->insert( subname, layer->subSymbol() );
00498     }
00499 
00500     saveProperties( layer->properties(), doc, layerEl );
00501     symEl.appendChild( layerEl );
00502   }
00503 
00504   return symEl;
00505 }
00506 
00507 
00508 QgsStringMap QgsSymbolLayerV2Utils::parseProperties( QDomElement& element )
00509 {
00510   QgsStringMap props;
00511   QDomElement e = element.firstChildElement();
00512   while ( !e.isNull() )
00513   {
00514     if ( e.tagName() != "prop" )
00515     {
00516       QgsDebugMsg( "unknown tag " + e.tagName() );
00517     }
00518     else
00519     {
00520       QString propKey = e.attribute( "k" );
00521       QString propValue = e.attribute( "v" );
00522       props[propKey] = propValue;
00523     }
00524     e = e.nextSiblingElement();
00525   }
00526   return props;
00527 }
00528 
00529 
00530 void QgsSymbolLayerV2Utils::saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element )
00531 {
00532   for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
00533   {
00534     QDomElement propEl = doc.createElement( "prop" );
00535     propEl.setAttribute( "k", it.key() );
00536     propEl.setAttribute( "v", it.value() );
00537     element.appendChild( propEl );
00538   }
00539 }
00540 
00541 QgsSymbolV2Map QgsSymbolLayerV2Utils::loadSymbols( QDomElement& element )
00542 {
00543   // go through symbols one-by-one and load them
00544 
00545   QgsSymbolV2Map symbols;
00546   QDomElement e = element.firstChildElement();
00547 
00548   while ( !e.isNull() )
00549   {
00550     if ( e.tagName() == "symbol" )
00551     {
00552       QgsSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol( e );
00553       if ( symbol != NULL )
00554         symbols.insert( e.attribute( "name" ), symbol );
00555     }
00556     else
00557     {
00558       QgsDebugMsg( "unknown tag: " + e.tagName() );
00559     }
00560     e = e.nextSiblingElement();
00561   }
00562 
00563 
00564   // now walk through the list of symbols and find those prefixed with @
00565   // these symbols are sub-symbols of some other symbol layers
00566   // e.g. symbol named "@[email protected]" is sub-symbol of layer 1 in symbol "foo"
00567   QStringList subsymbols;
00568 
00569   for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
00570   {
00571     if ( it.key()[0] != '@' )
00572       continue;
00573 
00574     // add to array (for deletion)
00575     subsymbols.append( it.key() );
00576 
00577     QStringList parts = it.key().split( "@" );
00578     if ( parts.count() < 3 )
00579     {
00580       QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
00581       delete it.value(); // we must delete it
00582       continue; // some invalid syntax
00583     }
00584     QString symname = parts[1];
00585     int symlayer = parts[2].toInt();
00586 
00587     if ( !symbols.contains( symname ) )
00588     {
00589       QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
00590       delete it.value(); // we must delete it
00591       continue;
00592     }
00593 
00594     QgsSymbolV2* sym = symbols[symname];
00595     if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
00596     {
00597       QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
00598       delete it.value(); // we must delete it
00599       continue;
00600     }
00601 
00602     // set subsymbol takes ownership
00603     bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
00604     if ( !res )
00605     {
00606       QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
00607     }
00608 
00609 
00610   }
00611 
00612   // now safely remove sub-symbol entries (they have been already deleted or the ownership was taken away)
00613   for ( int i = 0; i < subsymbols.count(); i++ )
00614     symbols.take( subsymbols[i] );
00615 
00616   return symbols;
00617 }
00618 
00619 QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString tagName, QDomDocument& doc )
00620 {
00621   QDomElement symbolsElem = doc.createElement( tagName );
00622 
00623   QMap<QString, QgsSymbolV2*> subSymbols;
00624 
00625   // save symbols
00626   for ( QMap<QString, QgsSymbolV2*>::iterator its = symbols.begin(); its != symbols.end(); ++its )
00627   {
00628     QDomElement symEl = saveSymbol( its.key(), its.value(), doc, &subSymbols );
00629     symbolsElem.appendChild( symEl );
00630   }
00631 
00632   // add subsymbols, don't allow subsymbols for them (to keep things simple)
00633   for ( QMap<QString, QgsSymbolV2*>::iterator itsub = subSymbols.begin(); itsub != subSymbols.end(); ++itsub )
00634   {
00635     QDomElement subsymEl = saveSymbol( itsub.key(), itsub.value(), doc );
00636     symbolsElem.appendChild( subsymEl );
00637   }
00638 
00639   return symbolsElem;
00640 }
00641 
00642 void QgsSymbolLayerV2Utils::clearSymbolMap( QgsSymbolV2Map& symbols )
00643 {
00644   foreach( QString name, symbols.keys() )
00645   delete symbols.value( name );
00646   symbols.clear();
00647 }
00648 
00649 
00650 QgsVectorColorRampV2* QgsSymbolLayerV2Utils::loadColorRamp( QDomElement& element )
00651 {
00652   QString rampType = element.attribute( "type" );
00653 
00654   // parse properties
00655   QgsStringMap props = QgsSymbolLayerV2Utils::parseProperties( element );
00656 
00657   if ( rampType == "gradient" )
00658     return QgsVectorGradientColorRampV2::create( props );
00659   else if ( rampType == "random" )
00660     return QgsVectorRandomColorRampV2::create( props );
00661   else if ( rampType == "colorbrewer" )
00662     return QgsVectorColorBrewerColorRampV2::create( props );
00663   else
00664   {
00665     QgsDebugMsg( "unknown colorramp type " + rampType );
00666     return NULL;
00667   }
00668 }
00669 
00670 
00671 QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc )
00672 {
00673   QDomElement rampEl = doc.createElement( "colorramp" );
00674   rampEl.setAttribute( "type", ramp->type() );
00675   rampEl.setAttribute( "name", name );
00676 
00677   QgsSymbolLayerV2Utils::saveProperties( ramp->properties(), doc, rampEl );
00678   return rampEl;
00679 }
00680 
00681 double QgsSymbolLayerV2Utils::lineWidthScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
00682 {
00683 
00684   if ( u == QgsSymbolV2::MM )
00685   {
00686     return c.scaleFactor();
00687   }
00688   else //QgsSymbol::MapUnit
00689   {
00690     double mup = c.mapToPixel().mapUnitsPerPixel();
00691     if ( mup > 0 )
00692     {
00693       return 1.0 / mup;
00694     }
00695     else
00696     {
00697       return 1.0;
00698     }
00699   }
00700 }
00701 
00702 double QgsSymbolLayerV2Utils::pixelSizeScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
00703 {
00704   if ( u == QgsSymbolV2::MM )
00705   {
00706     return ( c.scaleFactor() * c.rasterScaleFactor() );
00707   }
00708   else //QgsSymbol::MapUnit
00709   {
00710     double mup = c.mapToPixel().mapUnitsPerPixel();
00711     if ( mup > 0 )
00712     {
00713       return c.rasterScaleFactor() / c.mapToPixel().mapUnitsPerPixel();
00714     }
00715     else
00716     {
00717       return 1.0;
00718     }
00719   }
00720 }
00721 
00722 QgsRenderContext QgsSymbolLayerV2Utils::createRenderContext( QPainter* p )
00723 {
00724   QgsRenderContext context;
00725   context.setPainter( p );
00726   context.setRasterScaleFactor( 1.0 );
00727   if ( p && p->device() )
00728   {
00729     context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
00730   }
00731   else
00732   {
00733     context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
00734   }
00735   return context;
00736 }
00737 
00738 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
00739 {
00740   if ( !image )
00741   {
00742     return;
00743   }
00744 
00745   QRgb myRgb;
00746   QImage::Format format = image->format();
00747   if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
00748   {
00749     QgsDebugMsg( "no alpha channel." );
00750     return;
00751   }
00752 
00753   //change the alpha component of every pixel
00754   for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
00755   {
00756     QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
00757     for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
00758     {
00759       myRgb = scanLine[widthIndex];
00760       if ( format == QImage::Format_ARGB32_Premultiplied )
00761         scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
00762       else
00763         scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
00764     }
00765   }
00766 }
00767 
00768 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
00769 {
00770   switch( lhs.type() )
00771   {
00772   case QVariant::Int:
00773     return lhs.toInt() < rhs.toInt();
00774   case QVariant::UInt:
00775     return lhs.toUInt() < rhs.toUInt();
00776   case QVariant::LongLong:
00777     return lhs.toLongLong() < rhs.toLongLong();
00778   case QVariant::ULongLong:
00779     return lhs.toULongLong() < rhs.toULongLong();
00780   case QVariant::Double:
00781     return lhs.toDouble() < rhs.toDouble();
00782   case QVariant::Char:
00783     return lhs.toChar() < rhs.toChar();
00784   case QVariant::Date:
00785     return lhs.toDate() < rhs.toDate();
00786   case QVariant::Time:
00787     return lhs.toTime() < rhs.toTime();
00788   case QVariant::DateTime:
00789     return lhs.toDateTime() < rhs.toDateTime();
00790   default:
00791     return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
00792   }
00793 }
00794 
00795 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
00796 {
00797   return ! _QVariantLessThan( lhs, rhs);
00798 }
00799 
00800 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
00801 {
00802   if (order == Qt::AscendingOrder)
00803   {
00804     qSort( list.begin(), list.end(), _QVariantLessThan );
00805   }
00806   else // Qt::DescendingOrder
00807   {
00808     qSort( list.begin(), list.end(), _QVariantGreaterThan );
00809   }
00810 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines