Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Go to the documentation of this file.
00001 
00002 #include "qgsmarkersymbollayerv2.h"
00003 #include "qgssymbollayerv2utils.h"
00004 
00005 #include "qgsrendercontext.h"
00006 #include "qgsapplication.h"
00007 #include "qgslogger.h"
00008 #include "qgsproject.h"
00009 
00010 #include <QPainter>
00011 #include <QSvgRenderer>
00012 #include <QFileInfo>
00013 #include <QDir>
00014 
00015 #include <cmath>
00016 
00017 // MSVC compiler doesn't have defined M_PI in math.h
00018 #ifndef M_PI
00019 #define M_PI          3.14159265358979323846
00020 #endif
00021 
00022 #define DEG2RAD(x)    ((x)*M_PI/180)
00023 
00024 
00025 static QPointF _rotatedOffset( const QPointF& offset, double angle )
00026 {
00027   angle = DEG2RAD( angle );
00028   double c = cos( angle ), s = sin( angle );
00029   return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
00030 }
00031 
00033 
00034 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle )
00035 {
00036   mName = name;
00037   mColor = color;
00038   mBorderColor = borderColor;
00039   mSize = size;
00040   mAngle = angle;
00041   mOffset = QPointF( 0, 0 );
00042 }
00043 
00044 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& props )
00045 {
00046   QString name = DEFAULT_SIMPLEMARKER_NAME;
00047   QColor color = DEFAULT_SIMPLEMARKER_COLOR;
00048   QColor borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
00049   double size = DEFAULT_SIMPLEMARKER_SIZE;
00050   double angle = DEFAULT_SIMPLEMARKER_ANGLE;
00051 
00052   if ( props.contains( "name" ) )
00053     name = props["name"];
00054   if ( props.contains( "color" ) )
00055     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00056   if ( props.contains( "color_border" ) )
00057     borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00058   if ( props.contains( "size" ) )
00059     size = props["size"].toDouble();
00060   if ( props.contains( "angle" ) )
00061     angle = props["angle"].toDouble();
00062 
00063   QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle );
00064   if ( props.contains( "offset" ) )
00065     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00066   return m;
00067 }
00068 
00069 
00070 QString QgsSimpleMarkerSymbolLayerV2::layerType() const
00071 {
00072   return "SimpleMarker";
00073 }
00074 
00075 void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00076 {
00077   QColor brushColor = mColor;
00078   QColor penColor = mBorderColor;
00079   if ( context.alpha() < 1 )
00080   {
00081     penColor.setAlphaF( context.alpha() );
00082     brushColor.setAlphaF( context.alpha() );
00083   }
00084   mBrush = QBrush( brushColor );
00085   mPen = QPen( penColor );
00086   mPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
00087 
00088   QColor selBrushColor = context.selectionColor();
00089   QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
00090   if ( context.alpha() < 1 )
00091   {
00092     selBrushColor.setAlphaF( context.alpha() );
00093     selPenColor.setAlphaF( context.alpha() );
00094   }
00095   mSelBrush = QBrush( selBrushColor );
00096   mSelPen = QPen( selPenColor );
00097   mSelPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
00098 
00099   bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
00100   bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00101 
00102   // use caching only when:
00103   // - the size and rotation is not data-defined
00104   // - drawing to screen (not printer)
00105   mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput();
00106 
00107   // use either QPolygonF or QPainterPath for drawing
00108   // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
00109   if ( !prepareShape() ) // drawing as a polygon
00110   {
00111     if ( preparePath() ) // drawing as a painter path
00112     {
00113       // some markers can't be drawn as a polygon (circle, cross)
00114       // For these set the selected border color to the selected color
00115 
00116       if ( mName != "circle" )
00117         mSelPen.setColor( selBrushColor );
00118     }
00119     else
00120     {
00121       QgsDebugMsg( "unknown symbol" );
00122       return;
00123     }
00124   }
00125 
00126   QMatrix transform;
00127 
00128   // scale the shape (if the size is not going to be modified)
00129   if ( !hasDataDefinedSize )
00130   {
00131     double scaledSize = context.outputLineWidth( mSize );
00132     if ( mUsingCache )
00133       scaledSize *= context.renderContext().rasterScaleFactor();
00134     double half = scaledSize / 2.0;
00135     transform.scale( half, half );
00136   }
00137 
00138   // rotate if the rotation is not going to be changed during the rendering
00139   if ( !hasDataDefinedRotation && mAngle != 0 )
00140   {
00141     transform.rotate( mAngle );
00142   }
00143 
00144   if ( !mPolygon.isEmpty() )
00145     mPolygon = transform.map( mPolygon );
00146   else
00147     mPath = transform.map( mPath );
00148 
00149   if ( mUsingCache )
00150   {
00151     prepareCache( context );
00152   }
00153   else
00154   {
00155     mCache = QImage();
00156     mSelCache = QImage();
00157   }
00158 }
00159 
00160 
00161 void QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& context )
00162 {
00163   double scaledSize = context.outputPixelSize( mSize );
00164 
00165   // calculate necessary image size for the cache
00166   double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
00167   int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1; //  make image width, height odd; account for pen width
00168 
00169   double center = (( double ) imageSize / 2 ) + 0.5; // add 1/2 pixel for proper rounding when the figure's coordinates are added
00170 
00171   mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00172   mCache.fill( 0 );
00173 
00174   QPainter p;
00175   p.begin( &mCache );
00176   p.setRenderHint( QPainter::Antialiasing );
00177   p.setBrush( mBrush );
00178   p.setPen( mPen );
00179   p.translate( QPointF( center, center ) );
00180   drawMarker( &p, context );
00181   p.end();
00182 
00183   // Construct the selected version of the Cache
00184 
00185   QColor selColor = context.selectionColor();
00186 
00187   mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00188   mSelCache.fill( 0 );
00189 
00190   p.begin( &mSelCache );
00191   p.setRenderHint( QPainter::Antialiasing );
00192   p.setBrush( mSelBrush );
00193   p.setPen( mSelPen );
00194   p.translate( QPointF( center, center ) );
00195   drawMarker( &p, context );
00196   p.end();
00197 
00198   // Check that the selected version is different.  If not, then re-render,
00199   // filling the background with the selection color and using the normal
00200   // colors for the symbol .. could be ugly!
00201 
00202   if ( mSelCache == mCache )
00203   {
00204     p.begin( &mSelCache );
00205     p.setRenderHint( QPainter::Antialiasing );
00206     p.fillRect( 0, 0, imageSize, imageSize, selColor );
00207     p.setBrush( mBrush );
00208     p.setPen( mPen );
00209     p.translate( QPointF( center, center ) );
00210     drawMarker( &p, context );
00211     p.end();
00212   }
00213 }
00214 
00215 void QgsSimpleMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00216 {
00217 }
00218 
00219 bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
00220 {
00221   mPolygon.clear();
00222 
00223   if ( mName == "rectangle" )
00224   {
00225     mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
00226     return true;
00227   }
00228   else if ( mName == "diamond" )
00229   {
00230     mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
00231     << QPointF( 1, 0 ) << QPointF( 0, -1 );
00232     return true;
00233   }
00234   else if ( mName == "pentagon" )
00235   {
00236     mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
00237     << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
00238     << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
00239     << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
00240     << QPointF( 0, -1 );
00241     return true;
00242   }
00243   else if ( mName == "triangle" )
00244   {
00245     mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
00246     return true;
00247   }
00248   else if ( mName == "equilateral_triangle" )
00249   {
00250     mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
00251     << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
00252     << QPointF( 0, -1 );
00253     return true;
00254   }
00255   else if ( mName == "star" )
00256   {
00257     double sixth = 1.0 / 3;
00258 
00259     mPolygon << QPointF( 0, -1 )
00260     << QPointF( -sixth, -sixth )
00261     << QPointF( -1, -sixth )
00262     << QPointF( -sixth, 0 )
00263     << QPointF( -1, 1 )
00264     << QPointF( 0, + sixth )
00265     << QPointF( 1, 1 )
00266     << QPointF( + sixth, 0 )
00267     << QPointF( 1, -sixth )
00268     << QPointF( + sixth, -sixth );
00269     return true;
00270   }
00271   else if ( mName == "regular_star" )
00272   {
00273     double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
00274 
00275     mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) )  // 324
00276     << QPointF( sin( DEG2RAD( 288.0 ) ) , - cos( DEG2RAD( 288 ) ) )    // 288
00277     << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) )   // 252
00278     << QPointF( sin( DEG2RAD( 216.0 ) ) , - cos( DEG2RAD( 216.0 ) ) )   // 216
00279     << QPointF( 0, inner_r )         // 180
00280     << QPointF( sin( DEG2RAD( 144.0 ) ) , - cos( DEG2RAD( 144.0 ) ) )   // 144
00281     << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) )   // 108
00282     << QPointF( sin( DEG2RAD( 72.0 ) ) , - cos( DEG2RAD( 72.0 ) ) )    //  72
00283     << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) )   //  36
00284     << QPointF( 0, -1 );          //   0
00285     return true;
00286   }
00287   else if ( mName == "arrow" )
00288   {
00289     mPolygon
00290     << QPointF( 0, -1 )
00291     << QPointF( 0.5,  -0.5 )
00292     << QPointF( 0.25, -0.25 )
00293     << QPointF( 0.25,  1 )
00294     << QPointF( -0.25,  1 )
00295     << QPointF( -0.25, -0.5 )
00296     << QPointF( -0.5,  -0.5 );
00297     return true;
00298   }
00299   else if ( mName == "filled_arrowhead" )
00300   {
00301     mPolygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
00302     return true;
00303   }
00304 
00305   return false;
00306 }
00307 
00308 bool QgsSimpleMarkerSymbolLayerV2::preparePath()
00309 {
00310   mPath = QPainterPath();
00311 
00312   if ( mName == "circle" )
00313   {
00314     mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
00315     return true;
00316   }
00317   else if ( mName == "cross" )
00318   {
00319     mPath.moveTo( -1, 0 );
00320     mPath.lineTo( 1, 0 ); // horizontal
00321     mPath.moveTo( 0, -1 );
00322     mPath.lineTo( 0, 1 ); // vertical
00323     return true;
00324   }
00325   else if ( mName == "cross2" )
00326   {
00327     mPath.moveTo( -1, -1 );
00328     mPath.lineTo( 1, 1 );
00329     mPath.moveTo( 1, -1 );
00330     mPath.lineTo( -1, 1 );
00331     return true;
00332   }
00333   else if ( mName == "line" )
00334   {
00335     mPath.moveTo( 0, -1 );
00336     mPath.lineTo( 0, 1 ); // vertical line
00337     return true;
00338   }
00339   else if ( mName == "arrowhead" )
00340   {
00341     mPath.moveTo( 0, 0 );
00342     mPath.lineTo( -1, -1 );
00343     mPath.moveTo( 0, 0 );
00344     mPath.lineTo( -1, 1 );
00345     return true;
00346   }
00347 
00348   return false;
00349 }
00350 
00351 void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00352 {
00353   QgsRenderContext& rc = context.renderContext();
00354   QPainter* p = rc.painter();
00355   if ( !p )
00356   {
00357     return;
00358   }
00359 
00360   QPointF off( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00361   if ( mAngle )
00362     off = _rotatedOffset( off, mAngle );
00363 
00364   if ( mUsingCache )
00365   {
00366     // we will use cached image
00367     QImage &img = context.selected() ? mSelCache : mCache;
00368     double s = img.width() / context.renderContext().rasterScaleFactor();
00369     p->drawImage( QRectF( point.x() - s / 2.0 + off.x(),
00370                           point.y() - s / 2.0 + off.y(),
00371                           s, s ), img );
00372   }
00373   else
00374   {
00375     QMatrix transform;
00376 
00377     // bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
00378     bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00379 
00380     // move to the desired position
00381     transform.translate( point.x() + off.x(), point.y() + off.y() );
00382 
00383     // resize if necessary
00384     if ( hasDataDefinedSize )
00385     {
00386       double scaledSize = context.outputLineWidth( mSize );
00387       double half = scaledSize / 2.0;
00388       transform.scale( half, half );
00389     }
00390 
00391     // rotate if necessary
00392     if ( mAngle != 0 )
00393     {
00394       transform.rotate( mAngle );
00395     }
00396 
00397     p->setBrush( context.selected() ? mSelBrush : mBrush );
00398     p->setPen( context.selected() ? mSelPen : mPen );
00399 
00400     if ( !mPolygon.isEmpty() )
00401       p->drawPolygon( transform.map( mPolygon ) );
00402     else
00403       p->drawPath( transform.map( mPath ) );
00404   }
00405 }
00406 
00407 
00408 QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
00409 {
00410   QgsStringMap map;
00411   map["name"] = mName;
00412   map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00413   map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00414   map["size"] = QString::number( mSize );
00415   map["angle"] = QString::number( mAngle );
00416   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00417   return map;
00418 }
00419 
00420 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
00421 {
00422   QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle );
00423   m->setOffset( mOffset );
00424   return m;
00425 }
00426 
00427 void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
00428 {
00429   if ( mPolygon.count() != 0 )
00430   {
00431     p->drawPolygon( mPolygon );
00432   }
00433   else
00434   {
00435     p->drawPath( mPath );
00436   }
00437 }
00438 
00439 
00441 
00442 
00443 QgsSvgMarkerSymbolLayerV2::QgsSvgMarkerSymbolLayerV2( QString name, double size, double angle )
00444 {
00445   mPath = symbolNameToPath( name );
00446   mSize = size;
00447   mAngle = angle;
00448   mOffset = QPointF( 0, 0 );
00449 }
00450 
00451 
00452 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
00453 {
00454   QString name = DEFAULT_SVGMARKER_NAME;
00455   double size = DEFAULT_SVGMARKER_SIZE;
00456   double angle = DEFAULT_SVGMARKER_ANGLE;
00457 
00458   if ( props.contains( "name" ) )
00459     name = props["name"];
00460   if ( props.contains( "size" ) )
00461     size = props["size"].toDouble();
00462   if ( props.contains( "angle" ) )
00463     angle = props["angle"].toDouble();
00464 
00465   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle );
00466   if ( props.contains( "offset" ) )
00467     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00468   return m;
00469 }
00470 
00471 
00472 QString QgsSvgMarkerSymbolLayerV2::layerType() const
00473 {
00474   return "SvgMarker";
00475 }
00476 
00477 void QgsSvgMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00478 {
00479   double pictureSize = 0;
00480   QgsRenderContext& rc = context.renderContext();
00481 
00482   if ( rc.painter() && rc.painter()->device() )
00483   {
00484     //correct QPictures DPI correction
00485     pictureSize = context.outputLineWidth( mSize ) / rc.painter()->device()->logicalDpiX() * mPicture.logicalDpiX();
00486   }
00487   else
00488   {
00489     pictureSize = context.outputLineWidth( mSize );
00490   }
00491   QRectF rect( QPointF( -pictureSize / 2.0, -pictureSize / 2.0 ), QSizeF( pictureSize, pictureSize ) );
00492   QSvgRenderer renderer( mPath );
00493   QPainter painter( &mPicture );
00494   renderer.render( &painter, rect );
00495   QPainter selPainter( &mSelPicture );
00496   selPainter.setRenderHint( QPainter::Antialiasing );
00497   selPainter.setBrush( QBrush( context.selectionColor() ) );
00498   selPainter.setPen( Qt::NoPen );
00499   selPainter.drawEllipse( QPointF( 0, 0 ), pictureSize*0.6, pictureSize*0.6 );
00500   renderer.render( &selPainter, rect );
00501 
00502   mOrigSize = mSize; // save in case the size would be data defined
00503 }
00504 
00505 void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00506 {
00507 }
00508 
00509 
00510 void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00511 {
00512   QPainter* p = context.renderContext().painter();
00513   if ( !p )
00514   {
00515     return;
00516   }
00517 
00518   p->save();
00519   QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00520   if ( mAngle )
00521     outputOffset = _rotatedOffset( outputOffset, mAngle );
00522   p->translate( point + outputOffset );
00523 
00524   if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
00525   {
00526     double s = mSize / mOrigSize;
00527     p->scale( s, s );
00528   }
00529 
00530   if ( mAngle != 0 )
00531     p->rotate( mAngle );
00532 
00533   QPicture &pct = context.selected() ? mSelPicture : mPicture;
00534   p->drawPicture( 0, 0, pct );
00535 
00536   p->restore();
00537 }
00538 
00539 
00540 QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
00541 {
00542   QgsStringMap map;
00543   map["name"] = symbolPathToName( mPath );
00544   map["size"] = QString::number( mSize );
00545   map["angle"] = QString::number( mAngle );
00546   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00547   return map;
00548 }
00549 
00550 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
00551 {
00552   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle );
00553   m->setOffset( mOffset );
00554   return m;
00555 }
00556 
00557 
00558 QStringList QgsSvgMarkerSymbolLayerV2::listSvgFiles()
00559 {
00560   // copied from QgsMarkerCatalogue - TODO: unify
00561   QStringList list;
00562   QStringList svgPaths = QgsApplication::svgPaths();
00563 
00564   for ( int i = 0; i < svgPaths.size(); i++ )
00565   {
00566     QDir dir( svgPaths[i] );
00567     foreach( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
00568     {
00569       svgPaths.insert( i + 1, dir.path() + "/" + item );
00570     }
00571 
00572     foreach( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
00573     {
00574       // TODO test if it is correct SVG
00575       list.append( dir.path() + "/" + item );
00576     }
00577   }
00578   return list;
00579 }
00580 
00581 QString QgsSvgMarkerSymbolLayerV2::symbolNameToPath( QString name )
00582 {
00583   // copied from QgsSymbol::setNamedPointSymbol - TODO: unify
00584 
00585   // we might have a full path...
00586   if ( QFile( name ).exists() )
00587     return QFileInfo( name ).canonicalFilePath();
00588 
00589   // SVG symbol not found - probably a relative path was used
00590 
00591   QStringList svgPaths = QgsApplication::svgPaths();
00592   for ( int i = 0; i < svgPaths.size(); i++ )
00593   {
00594     QgsDebugMsg( "SvgPath: " + svgPaths[i] );
00595     QFileInfo myInfo( name );
00596     QString myFileName = myInfo.fileName(); // foo.svg
00597     QString myLowestDir = myInfo.dir().dirName();
00598     QString myLocalPath = svgPaths[i] + "/" + myLowestDir + "/" + myFileName;
00599 
00600     QgsDebugMsg( "Alternative svg path: " + myLocalPath );
00601     if ( QFile( myLocalPath ).exists() )
00602     {
00603       QgsDebugMsg( "Svg found in alternative path" );
00604       return QFileInfo( myLocalPath ).canonicalFilePath();
00605     }
00606     else if ( myInfo.isRelative() )
00607     {
00608       QFileInfo pfi( QgsProject::instance()->fileName() );
00609       QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
00610       if ( pfi.exists() && QFile( alternatePath ).exists() )
00611       {
00612         QgsDebugMsg( "Svg found in alternative path" );
00613         return QFileInfo( alternatePath ).canonicalFilePath();
00614       }
00615       else
00616       {
00617         QgsDebugMsg( "Svg not found in project path" );
00618       }
00619     }
00620     else
00621     {
00622       //couldnt find the file, no happy ending :-(
00623       QgsDebugMsg( "Computed alternate path but no svg there either" );
00624     }
00625   }
00626   return QString();
00627 }
00628 
00629 QString QgsSvgMarkerSymbolLayerV2::symbolPathToName( QString path )
00630 {
00631   // copied from QgsSymbol::writeXML
00632 
00633   QFileInfo fi( path );
00634   if ( !fi.exists() )
00635     return path;
00636 
00637   path = fi.canonicalFilePath();
00638 
00639   QStringList svgPaths = QgsApplication::svgPaths();
00640 
00641   for ( int i = 0; i < svgPaths.size(); i++ )
00642   {
00643     QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
00644 
00645     if ( !dir.isEmpty() && path.startsWith( dir ) )
00646     {
00647       path = path.mid( dir.size() );
00648       break;
00649     }
00650   }
00651 
00652   return path;
00653 }
00654 
00655 
00657 
00658 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
00659 {
00660   mFontFamily = fontFamily;
00661   mChr = chr;
00662   mColor = color;
00663   mAngle = angle;
00664   mSize = pointSize;
00665   mOffset = QPointF( 0, 0 );
00666 }
00667 
00668 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props )
00669 {
00670   QString fontFamily = DEFAULT_FONTMARKER_FONT;
00671   QChar chr = DEFAULT_FONTMARKER_CHR;
00672   double pointSize = DEFAULT_FONTMARKER_SIZE;
00673   QColor color = DEFAULT_FONTMARKER_COLOR;
00674   double angle = DEFAULT_FONTMARKER_ANGLE;
00675 
00676   if ( props.contains( "font" ) )
00677     fontFamily = props["font"];
00678   if ( props.contains( "chr" ) && props["chr"].length() > 0 )
00679     chr = props["chr"].at( 0 );
00680   if ( props.contains( "size" ) )
00681     pointSize = props["size"].toDouble();
00682   if ( props.contains( "color" ) )
00683     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00684   if ( props.contains( "angle" ) )
00685     angle = props["angle"].toDouble();
00686 
00687   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
00688   if ( props.contains( "offset" ) )
00689     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00690   return m;
00691 }
00692 
00693 QString QgsFontMarkerSymbolLayerV2::layerType() const
00694 {
00695   return "FontMarker";
00696 }
00697 
00698 void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00699 {
00700   mFont = QFont( mFontFamily );
00701   mFont.setPixelSize( context.outputLineWidth( mSize ) );
00702   QFontMetrics fm( mFont );
00703   mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
00704 
00705   mOrigSize = mSize; // save in case the size would be data defined
00706 }
00707 
00708 void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00709 {
00710 }
00711 
00712 void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00713 {
00714   QPainter* p = context.renderContext().painter();
00715   QColor penColor = context.selected() ? context.selectionColor() : mColor;
00716   penColor.setAlphaF( context.alpha() );
00717   p->setPen( penColor );
00718   p->setFont( mFont );
00719 
00720 
00721   p->save();
00722   QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00723   if ( mAngle )
00724     outputOffset = _rotatedOffset( outputOffset, mAngle );
00725   p->translate( point + outputOffset );
00726 
00727   if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
00728   {
00729     double s = mSize / mOrigSize;
00730     p->scale( s, s );
00731   }
00732 
00733   if ( mAngle != 0 )
00734     p->rotate( mAngle );
00735 
00736   p->drawText( -mChrOffset, mChr );
00737   p->restore();
00738 }
00739 
00740 QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
00741 {
00742   QgsStringMap props;
00743   props["font"] = mFontFamily;
00744   props["chr"] = mChr;
00745   props["size"] = QString::number( mSize );
00746   props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00747   props["angle"] = QString::number( mAngle );
00748   props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00749   return props;
00750 }
00751 
00752 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
00753 {
00754   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( mFontFamily, mChr, mSize, mColor, mAngle );
00755   m->setOffset( mOffset );
00756   return m;
00757 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines