Quantum GIS API Documentation
1.7.4
|
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 "@foo@1" 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 }