Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgssymbolv2.cpp
Go to the documentation of this file.
00001 
00002 #include "qgsrenderer.h"
00003 #include "qgssymbolv2.h"
00004 #include "qgssymbollayerv2.h"
00005 
00006 #include "qgslinesymbollayerv2.h"
00007 #include "qgsmarkersymbollayerv2.h"
00008 #include "qgsfillsymbollayerv2.h"
00009 
00010 #include "qgslogger.h"
00011 #include "qgsrendercontext.h" // for bigSymbolPreview
00012 
00013 #include <QColor>
00014 #include <QImage>
00015 #include <QPainter>
00016 #include <QSize>
00017 
00018 #include <cmath>
00019 
00020 QgsSymbolV2::QgsSymbolV2( SymbolType type, QgsSymbolLayerV2List layers )
00021     : mType( type ), mLayers( layers ), mOutputUnit( MM ), mAlpha( 1.0 ), mRenderHints( 0 )
00022 {
00023 
00024   // check they're all correct symbol layers
00025   for ( int i = 0; i < mLayers.count(); i++ )
00026   {
00027     if ( mLayers[i] == NULL )
00028     {
00029       mLayers.removeAt( i-- );
00030     }
00031     else if ( !isSymbolLayerCompatible( mLayers[i]->type() ) )
00032     {
00033       delete mLayers[i];
00034       mLayers.removeAt( i-- );
00035     }
00036   }
00037 
00038 }
00039 
00040 QgsSymbolV2::~QgsSymbolV2()
00041 {
00042   // delete all symbol layers (we own them, so it's okay)
00043   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00044     delete *it;
00045 }
00046 
00047 QgsSymbolV2* QgsSymbolV2::defaultSymbol( QGis::GeometryType geomType )
00048 {
00049   QgsSymbolV2* s;
00050   switch ( geomType )
00051   {
00052     case QGis::Point: s = new QgsMarkerSymbolV2(); break;
00053     case QGis::Line:  s = new QgsLineSymbolV2(); break;
00054     case QGis::Polygon: s = new QgsFillSymbolV2(); break;
00055     default: QgsDebugMsg( "unknown layer's geometry type" ); return NULL;
00056   }
00057 
00058   s->setColor( QColor::fromHsv( rand() % 360, 64 + rand() % 192, 128 + rand() % 128 ) );
00059   return s;
00060 }
00061 
00062 
00063 QgsSymbolLayerV2* QgsSymbolV2::symbolLayer( int layer )
00064 {
00065   if ( layer < 0 || layer >= mLayers.count() )
00066     return NULL;
00067 
00068   return mLayers[layer];
00069 }
00070 
00071 
00072 bool QgsSymbolV2::isSymbolLayerCompatible( SymbolType t )
00073 {
00074   // fill symbol can contain also line symbol layers for drawing of outlines
00075   if ( mType == Fill && t == Line )
00076     return true;
00077 
00078   return mType == t;
00079 }
00080 
00081 
00082 bool QgsSymbolV2::insertSymbolLayer( int index, QgsSymbolLayerV2* layer )
00083 {
00084   if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
00085     return false;
00086   if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
00087     return false;
00088 
00089   mLayers.insert( index, layer );
00090   return true;
00091 }
00092 
00093 
00094 bool QgsSymbolV2::appendSymbolLayer( QgsSymbolLayerV2* layer )
00095 {
00096   if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
00097     return false;
00098 
00099   mLayers.append( layer );
00100   return true;
00101 }
00102 
00103 
00104 bool QgsSymbolV2::deleteSymbolLayer( int index )
00105 {
00106   if ( index < 0 || index >= mLayers.count() )
00107     return false;
00108 
00109   delete mLayers[index];
00110   mLayers.removeAt( index );
00111   return true;
00112 }
00113 
00114 
00115 QgsSymbolLayerV2* QgsSymbolV2::takeSymbolLayer( int index )
00116 {
00117   if ( index < 0 || index >= mLayers.count() )
00118     return NULL;
00119 
00120   return mLayers.takeAt( index );
00121 }
00122 
00123 
00124 bool QgsSymbolV2::changeSymbolLayer( int index, QgsSymbolLayerV2* layer )
00125 {
00126   if ( index < 0 || index >= mLayers.count() )
00127     return false;
00128   if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
00129     return false;
00130 
00131   delete mLayers[index]; // first delete the original layer
00132   mLayers[index] = layer; // set new layer
00133   return true;
00134 }
00135 
00136 
00137 void QgsSymbolV2::startRender( QgsRenderContext& context )
00138 {
00139   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
00140   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00141     ( *it )->startRender( symbolContext );
00142 }
00143 
00144 void QgsSymbolV2::stopRender( QgsRenderContext& context )
00145 {
00146   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
00147   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00148     ( *it )->stopRender( symbolContext );
00149 }
00150 
00151 void QgsSymbolV2::setColor( const QColor& color )
00152 {
00153   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00154   {
00155     if ( !( *it )->isLocked() )
00156       ( *it )->setColor( color );
00157   }
00158 }
00159 
00160 QColor QgsSymbolV2::color()
00161 {
00162   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00163   {
00164     // return color of the first unlocked layer
00165     if ( !( *it )->isLocked() )
00166       return ( *it )->color();
00167   }
00168   return QColor( 0, 0, 0 );
00169 }
00170 
00171 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size )
00172 {
00173   QgsRenderContext context = QgsSymbolLayerV2Utils::createRenderContext( painter );
00174   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
00175   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00176   {
00177     if ( mType == Fill && ( *it )->type() == Line )
00178     {
00179       // line symbol layer would normally draw just a line
00180       // so we override this case to force it to draw a polygon outline
00181       QgsLineSymbolLayerV2* lsl = ( QgsLineSymbolLayerV2* ) * it;
00182 
00183       // from QgsFillSymbolLayerV2::drawPreviewIcon()
00184       QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
00185       lsl->startRender( symbolContext );
00186       lsl->renderPolygonOutline( poly, NULL, symbolContext );
00187       lsl->stopRender( symbolContext );
00188     }
00189     else
00190       ( *it )->drawPreviewIcon( symbolContext, size );
00191   }
00192 }
00193 
00194 
00195 QImage QgsSymbolV2::bigSymbolPreviewImage()
00196 {
00197   QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
00198   preview.fill( 0 );
00199 
00200   QPainter p( &preview );
00201   p.setRenderHint( QPainter::Antialiasing );
00202   p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
00203 
00204   if ( mType == QgsSymbolV2::Marker )
00205   {
00206     p.setPen( QPen( Qt::gray ) );
00207     p.drawLine( 0, 50, 100, 50 );
00208     p.drawLine( 50, 0, 50, 100 );
00209   }
00210 
00211   QgsRenderContext context = QgsSymbolLayerV2Utils::createRenderContext( &p );
00212   startRender( context );
00213 
00214   if ( mType == QgsSymbolV2::Line )
00215   {
00216     QPolygonF poly;
00217     poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
00218     static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, context );
00219   }
00220   else if ( mType == QgsSymbolV2::Fill )
00221   {
00222     QPolygonF polygon;
00223     polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
00224     static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, NULL, context );
00225   }
00226   else // marker
00227   {
00228     static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), context );
00229   }
00230 
00231   stopRender( context );
00232   return preview;
00233 }
00234 
00235 
00236 QString QgsSymbolV2::dump()
00237 {
00238   QString t;
00239   switch ( type() )
00240   {
00241     case QgsSymbolV2::Marker: t = "MARKER"; break;
00242     case QgsSymbolV2::Line: t = "LINE"; break;
00243     case QgsSymbolV2::Fill: t = "FILL"; break;
00244     default: Q_ASSERT( 0 && "unknown symbol type" );
00245   }
00246   QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
00247 
00248   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00249   {
00250     // TODO:
00251   }
00252   return s;
00253 }
00254 
00255 QgsSymbolLayerV2List QgsSymbolV2::cloneLayers() const
00256 {
00257   QgsSymbolLayerV2List lst;
00258   for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00259   {
00260     QgsSymbolLayerV2* layer = ( *it )->clone();
00261     layer->setLocked(( *it )->isLocked() );
00262     layer->setRenderingPass(( *it )->renderingPass() );
00263     lst.append( layer );
00264   }
00265   return lst;
00266 }
00267 
00269 
00270 QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected, int renderHints )
00271     : mRenderContext( c ), mOutputUnit( u ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints )
00272 {
00273 
00274 }
00275 
00276 QgsSymbolV2RenderContext::~QgsSymbolV2RenderContext()
00277 {
00278 
00279 }
00280 
00281 QColor QgsSymbolV2RenderContext::selectionColor()
00282 {
00283   return QgsRenderer::selectionColor();
00284 }
00285 
00286 
00287 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
00288 {
00289   return width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( mRenderContext, mOutputUnit );
00290 }
00291 
00292 double QgsSymbolV2RenderContext::outputPixelSize( double size ) const
00293 {
00294   return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit );
00295 }
00296 
00297 QgsSymbolV2RenderContext& QgsSymbolV2RenderContext::operator=( const QgsSymbolV2RenderContext& )
00298 {
00299   // This is just a dummy implementation of assignment.
00300   // sip 4.7 generates a piece of code that needs this function to exist.
00301   // It's not generated automatically by the compiler because of
00302   // mRenderContext member which is a reference (and thus can't be changed).
00303   Q_ASSERT( false );
00304   return *this;
00305 }
00306 
00308 
00309 QgsMarkerSymbolV2* QgsMarkerSymbolV2::createSimple( const QgsStringMap& properties )
00310 {
00311   QgsSymbolLayerV2* sl = QgsSimpleMarkerSymbolLayerV2::create( properties );
00312   if ( sl == NULL )
00313     return NULL;
00314 
00315   QgsSymbolLayerV2List layers;
00316   layers.append( sl );
00317   return new QgsMarkerSymbolV2( layers );
00318 }
00319 
00320 QgsLineSymbolV2* QgsLineSymbolV2::createSimple( const QgsStringMap& properties )
00321 {
00322   QgsSymbolLayerV2* sl = QgsSimpleLineSymbolLayerV2::create( properties );
00323   if ( sl == NULL )
00324     return NULL;
00325 
00326   QgsSymbolLayerV2List layers;
00327   layers.append( sl );
00328   return new QgsLineSymbolV2( layers );
00329 }
00330 
00331 QgsFillSymbolV2* QgsFillSymbolV2::createSimple( const QgsStringMap& properties )
00332 {
00333   QgsSymbolLayerV2* sl = QgsSimpleFillSymbolLayerV2::create( properties );
00334   if ( sl == NULL )
00335     return NULL;
00336 
00337   QgsSymbolLayerV2List layers;
00338   layers.append( sl );
00339   return new QgsFillSymbolV2( layers );
00340 }
00341 
00343 
00344 
00345 QgsMarkerSymbolV2::QgsMarkerSymbolV2( QgsSymbolLayerV2List layers )
00346     : QgsSymbolV2( Marker, layers )
00347 {
00348   if ( mLayers.count() == 0 )
00349     mLayers.append( new QgsSimpleMarkerSymbolLayerV2() );
00350 }
00351 
00352 void QgsMarkerSymbolV2::setAngle( double angle )
00353 {
00354   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00355   {
00356     QgsMarkerSymbolLayerV2* layer = ( QgsMarkerSymbolLayerV2* ) * it;
00357     layer->setAngle( angle );
00358   }
00359 }
00360 
00361 double QgsMarkerSymbolV2::angle()
00362 {
00363   QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
00364 
00365   if ( it == mLayers.end() )
00366     return 0;
00367 
00368   // return angle of the first symbol layer
00369   const QgsMarkerSymbolLayerV2 *layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
00370   return layer->angle();
00371 }
00372 
00373 void QgsMarkerSymbolV2::setSize( double s )
00374 {
00375   double origSize = size();
00376 
00377   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00378   {
00379     QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
00380     if ( layer->size() == origSize )
00381       layer->setSize( s );
00382     else
00383     {
00384       // proportionally scale size
00385       if ( origSize != 0 )
00386         layer->setSize( layer->size() * s / origSize );
00387     }
00388   }
00389 }
00390 
00391 double QgsMarkerSymbolV2::size()
00392 {
00393   // return size of the largest symbol
00394   double maxSize = 0;
00395   for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00396   {
00397     const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
00398     double lsize = layer->size();
00399     if ( lsize > maxSize )
00400       maxSize = lsize;
00401   }
00402   return maxSize;
00403 }
00404 
00405 void QgsMarkerSymbolV2::renderPoint( const QPointF& point, QgsRenderContext& context, int layer, bool selected )
00406 {
00407   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
00408   if ( layer != -1 )
00409   {
00410     if ( layer >= 0 && layer < mLayers.count() )
00411       (( QgsMarkerSymbolLayerV2* ) mLayers[layer] )->renderPoint( point, symbolContext );
00412     return;
00413   }
00414 
00415   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00416   {
00417     QgsMarkerSymbolLayerV2* layer = ( QgsMarkerSymbolLayerV2* ) * it;
00418     layer->renderPoint( point, symbolContext );
00419   }
00420 }
00421 
00422 QgsSymbolV2* QgsMarkerSymbolV2::clone() const
00423 {
00424   QgsSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
00425   cloneSymbol->setOutputUnit( mOutputUnit );
00426   cloneSymbol->setAlpha( mAlpha );
00427   return cloneSymbol;
00428 }
00429 
00430 
00432 // LINE
00433 
00434 QgsLineSymbolV2::QgsLineSymbolV2( QgsSymbolLayerV2List layers )
00435     : QgsSymbolV2( Line, layers )
00436 {
00437   if ( mLayers.count() == 0 )
00438     mLayers.append( new QgsSimpleLineSymbolLayerV2() );
00439 }
00440 
00441 void QgsLineSymbolV2::setWidth( double w )
00442 {
00443   double origWidth = width();
00444 
00445   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00446   {
00447     QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
00448     if ( layer->width() == origWidth )
00449     {
00450       layer->setWidth( w );
00451     }
00452     else
00453     {
00454       // proportionally scale the width
00455       if ( origWidth != 0 )
00456         layer->setWidth( layer->width() * w / origWidth );
00457     }
00458   }
00459 }
00460 
00461 double QgsLineSymbolV2::width()
00462 {
00463   double maxWidth = 0;
00464   for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00465   {
00466     const QgsLineSymbolLayerV2* layer = ( const QgsLineSymbolLayerV2* ) * it;
00467     double width = layer->width();
00468     if ( width > maxWidth )
00469       maxWidth = width;
00470   }
00471   return maxWidth;
00472 }
00473 
00474 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, QgsRenderContext& context, int layer, bool selected )
00475 {
00476   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
00477   if ( layer != -1 )
00478   {
00479     if ( layer >= 0 && layer < mLayers.count() )
00480       (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolyline( points, symbolContext );
00481     return;
00482   }
00483 
00484   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00485   {
00486     QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
00487     layer->renderPolyline( points, symbolContext );
00488   }
00489 }
00490 
00491 
00492 QgsSymbolV2* QgsLineSymbolV2::clone() const
00493 {
00494   QgsSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
00495   cloneSymbol->setOutputUnit( mOutputUnit );
00496   cloneSymbol->setAlpha( mAlpha );
00497   return cloneSymbol;
00498 }
00499 
00501 // FILL
00502 
00503 QgsFillSymbolV2::QgsFillSymbolV2( QgsSymbolLayerV2List layers )
00504     : QgsSymbolV2( Fill, layers )
00505 {
00506   if ( mLayers.count() == 0 )
00507     mLayers.append( new QgsSimpleFillSymbolLayerV2() );
00508 }
00509 
00510 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsRenderContext& context, int layer, bool selected )
00511 {
00512   QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
00513   if ( layer != -1 )
00514   {
00515     if ( layer >= 0 && layer < mLayers.count() )
00516     {
00517       QgsSymbolV2::SymbolType layertype = mLayers.at( layer )->type();
00518       if ( layertype == QgsSymbolV2::Fill )
00519         (( QgsFillSymbolLayerV2* ) mLayers[layer] )->renderPolygon( points, rings, symbolContext );
00520       else if ( layertype == QgsSymbolV2::Line )
00521         (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolygonOutline( points, rings, symbolContext );
00522     }
00523     return;
00524   }
00525 
00526   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00527   {
00528     QgsSymbolV2::SymbolType layertype = ( *it )->type();
00529     if ( layertype == QgsSymbolV2::Fill )
00530     {
00531       QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
00532       layer->renderPolygon( points, rings, symbolContext );
00533     }
00534     else if ( layertype == QgsSymbolV2::Line )
00535     {
00536       QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
00537       layer->renderPolygonOutline( points, rings, symbolContext );
00538     }
00539   }
00540 }
00541 
00542 
00543 QgsSymbolV2* QgsFillSymbolV2::clone() const
00544 {
00545   QgsSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
00546   cloneSymbol->setOutputUnit( mOutputUnit );
00547   cloneSymbol->setAlpha( mAlpha );
00548   return cloneSymbol;
00549 }
00550 
00551 void QgsFillSymbolV2::setAngle( double angle )
00552 {
00553   for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
00554   {
00555     QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
00556     layer->setAngle( angle );
00557   }
00558 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines