220 changes: 164 additions & 56 deletions src/gui/qgshighlight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@
* *
***************************************************************************/

#include "qgshighlight.h"
#include <typeinfo>
#include "qgsmarkersymbollayerv2.h"
#include "qgslinesymbollayerv2.h"

#include "qgscoordinatetransform.h"
#include "qgsgeometry.h"
#include "qgshighlight.h"
#include "qgsmapcanvas.h"
#include "qgsmaplayer.h"
#include "qgsmaprenderer.h"
#include "qgscoordinatetransform.h"
#include "qgsrendercontext.h"
#include "qgssymbollayerv2.h"
#include "qgssymbolv2.h"
#include "qgsvectorlayer.h"

/*!
Expand All @@ -29,6 +36,7 @@
QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsMapLayer *layer )
: QgsMapCanvasItem( mapCanvas )
, mLayer( layer )
, mRenderer( 0 )
{
mGeometry = geom ? new QgsGeometry( *geom ) : 0;
init();
Expand All @@ -37,19 +45,37 @@ QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsMapLa
QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsVectorLayer *layer )
: QgsMapCanvasItem( mapCanvas )
, mLayer( static_cast<QgsMapLayer *>( layer ) )
, mRenderer( 0 )
{
mGeometry = geom ? new QgsGeometry( *geom ) : 0;
init();
}

QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, const QgsFeature& feature, QgsVectorLayer *layer )
: QgsMapCanvasItem( mapCanvas )
, mGeometry( 0 )
, mLayer( static_cast<QgsMapLayer *>( layer ) )
, mFeature( feature )
, mRenderer( 0 )
{
init();
}

void QgsHighlight::init()
{
if ( mMapCanvas->mapRenderer()->hasCrsTransformEnabled() )
{
const QgsCoordinateTransform* ct = mMapCanvas->mapRenderer()->transformation( mLayer );
if ( ct )
{
mGeometry->transform( *ct );
if ( mGeometry )
{
mGeometry->transform( *ct );
}
else if ( mFeature.geometry() )
{
mFeature.geometry()->transform( *ct );
}
}
}
updateRect();
Expand All @@ -60,6 +86,7 @@ void QgsHighlight::init()
QgsHighlight::~QgsHighlight()
{
delete mGeometry;
delete mRenderer;
}

/*!
Expand All @@ -71,6 +98,51 @@ void QgsHighlight::setColor( const QColor & color )
QColor fillColor( color.red(), color.green(), color.blue(), 63 );
mBrush.setColor( fillColor );
mBrush.setStyle( Qt::SolidPattern );

delete mRenderer;
mRenderer = 0;
QgsVectorLayer *layer = vectorLayer();
if ( layer && layer->rendererV2() )
{
mRenderer = layer->rendererV2()->clone();
}
if ( mRenderer )
{
foreach ( QgsSymbolV2* symbol, mRenderer->symbols() )
{
if ( !symbol ) continue;
setSymbolColor( symbol, color );
}
}
}

void QgsHighlight::setSymbolColor( QgsSymbolV2* symbol, const QColor & color )
{
if ( !symbol ) return;

QColor fillColor( color.red(), color.green(), color.blue(), 63 );

for ( int i = symbol->symbolLayerCount() - 1; i >= 0; i-- )
{
QgsSymbolLayerV2* symbolLayer = symbol->symbolLayer( i );
if ( !symbolLayer ) continue;

if ( symbolLayer->subSymbol() )
{
setSymbolColor( symbolLayer->subSymbol(), color );
}
else
{
// We must insert additional highlight symbol layer above each original layer
// otherwise lower layers would become visible through transparent fill color.
QgsSymbolLayerV2* highlightLayer = symbolLayer->clone();

highlightLayer->setColor( color ); // line symbology layers
highlightLayer->setOutlineColor( color ); // marker and fill symbology layers
highlightLayer->setFillColor( fillColor ); // marker and fill symbology layers
symbol->insertSymbolLayer( i + 1, highlightLayer );
}
}
}

/*!
Expand Down Expand Up @@ -145,74 +217,96 @@ void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon )
*/
void QgsHighlight::paint( QPainter* p )
{
if ( !mGeometry )
{
return;
}

p->setPen( mPen );
p->setBrush( mBrush );

switch ( mGeometry->wkbType() )
if ( mGeometry )
{
case QGis::WKBPoint:
case QGis::WKBPoint25D:
{
paintPoint( p, mGeometry->asPoint() );
}
break;
p->setPen( mPen );
p->setBrush( mBrush );

case QGis::WKBMultiPoint:
case QGis::WKBMultiPoint25D:
switch ( mGeometry->wkbType() )
{
QgsMultiPoint m = mGeometry->asMultiPoint();
for ( int i = 0; i < m.size(); i++ )
case QGis::WKBPoint:
case QGis::WKBPoint25D:
{
paintPoint( p, m[i] );
paintPoint( p, mGeometry->asPoint() );
}
}
break;
break;

case QGis::WKBLineString:
case QGis::WKBLineString25D:
{
paintLine( p, mGeometry->asPolyline() );
}
break;
case QGis::WKBMultiPoint:
case QGis::WKBMultiPoint25D:
{
QgsMultiPoint m = mGeometry->asMultiPoint();
for ( int i = 0; i < m.size(); i++ )
{
paintPoint( p, m[i] );
}
}
break;

case QGis::WKBMultiLineString:
case QGis::WKBMultiLineString25D:
{
QgsMultiPolyline m = mGeometry->asMultiPolyline();
case QGis::WKBLineString:
case QGis::WKBLineString25D:
{
paintLine( p, mGeometry->asPolyline() );
}
break;

for ( int i = 0; i < m.size(); i++ )
case QGis::WKBMultiLineString:
case QGis::WKBMultiLineString25D:
{
paintLine( p, m[i] );
QgsMultiPolyline m = mGeometry->asMultiPolyline();

for ( int i = 0; i < m.size(); i++ )
{
paintLine( p, m[i] );
}
}
}
break;
break;

case QGis::WKBPolygon:
case QGis::WKBPolygon25D:
{
paintPolygon( p, mGeometry->asPolygon() );
}
break;
case QGis::WKBPolygon:
case QGis::WKBPolygon25D:
{
paintPolygon( p, mGeometry->asPolygon() );
}
break;

case QGis::WKBMultiPolygon:
case QGis::WKBMultiPolygon25D:
{
QgsMultiPolygon m = mGeometry->asMultiPolygon();
for ( int i = 0; i < m.size(); i++ )
case QGis::WKBMultiPolygon:
case QGis::WKBMultiPolygon25D:
{
paintPolygon( p, m[i] );
QgsMultiPolygon m = mGeometry->asMultiPolygon();
for ( int i = 0; i < m.size(); i++ )
{
paintPolygon( p, m[i] );
}
}
}
break;
break;

case QGis::WKBUnknown:
default:
return;
case QGis::WKBUnknown:
default:
return;
}
}
else if ( mFeature.geometry() && mRenderer )
{
QgsVectorLayer *layer = vectorLayer();
if ( layer )
{
QgsRenderContext context = *( mMapCanvas->mapRenderer()->rendererContext() );

// The context is local rectangle of QgsHighlight we previously set.
// Because QgsMapCanvasItem::setRect() adds 1 pixel on border we cannot simply
// use boundingRect().height() for QgsMapToPixel height.
QgsRectangle extent = rect();
double height = toCanvasCoordinates( QgsPoint( extent.xMinimum(), extent.yMinimum() ) ).y() - toCanvasCoordinates( QgsPoint( extent.xMinimum(), extent.yMaximum() ) ).y();

QgsMapToPixel mapToPixel = QgsMapToPixel( mMapCanvas->mapUnitsPerPixel(),
height, extent.yMinimum(), extent.xMinimum() );
context.setMapToPixel( mapToPixel );
context.setExtent( extent );
context.setCoordinateTransform( 0 ); // we reprojected geometry in init()
context.setPainter( p );
mRenderer->startRender( context, layer );
mRenderer->renderFeature( mFeature, context );
mRenderer->stopRender( context );
}
}
}

Expand All @@ -234,8 +328,22 @@ void QgsHighlight::updateRect()
setRect( r );
setVisible( mGeometry );
}
else if ( mFeature.geometry() )
{
// We are currently using full map canvas extent for two reasons:
// 1) currently there is no method in QgsFeatureRendererV2 to get rendered feature
// bounding box
// 2) using different extent would result in shifted fill patterns
setRect( mMapCanvas->extent() );
setVisible( true );
}
else
{
setRect( QgsRectangle() );
}
}

QgsVectorLayer * QgsHighlight::vectorLayer()
{
return dynamic_cast<QgsVectorLayer *>( mLayer );
}
17 changes: 17 additions & 0 deletions src/gui/qgshighlight.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#define QGSHIGHLIGHT_H

#include "qgsmapcanvasitem.h"
#include "qgsfeaturestore.h"
#include "qgsgeometry.h"
#include "qgsrendererv2.h"
#include <QBrush>
#include <QList>
#include <QPen>
Expand All @@ -25,6 +27,7 @@

class QgsMapLayer;
class QgsVectorLayer;
class QgsSymbolV2;

/** A class for highlight features on the map.
*/
Expand All @@ -33,9 +36,18 @@ class GUI_EXPORT QgsHighlight: public QgsMapCanvasItem
public:
QgsHighlight( QgsMapCanvas *mapCanvas, QgsGeometry *geom, QgsMapLayer *layer );
QgsHighlight( QgsMapCanvas *mapCanvas, QgsGeometry *geom, QgsVectorLayer *layer );
/** Constructor for highlighting true feature shape using feature attributes
* and renderer.
* @param mapCanvas map canvas
* @param feature
* @param layer vector layer
*/
QgsHighlight( QgsMapCanvas *mapCanvas, const QgsFeature& feature, QgsVectorLayer *layer );
~QgsHighlight();

void setColor( const QColor & color );

/** Set width. Ignored in feature mode. */
void setWidth( int width );

protected:
Expand All @@ -46,16 +58,21 @@ class GUI_EXPORT QgsHighlight: public QgsMapCanvasItem

private:
void init();
void setSymbolColor( QgsSymbolV2* symbol, const QColor & color );
void paintPoint( QPainter *p, QgsPoint point );
void paintLine( QPainter *p, QgsPolyline line );
void paintPolygon( QPainter *p, QgsPolygon polygon );

QgsVectorLayer *vectorLayer();

QgsHighlight();

QBrush mBrush;
QPen mPen;
QgsGeometry *mGeometry;
QgsMapLayer *mLayer;
QgsFeature mFeature;
QgsFeatureRendererV2 *mRenderer;
};

#endif