highlight identified feature using real feature shape

This commit is contained in:
Radim Blazek 2014-01-12 18:17:20 +01:00
parent d59ab80522
commit a18b4a35c6
15 changed files with 304 additions and 72 deletions

View File

@ -28,6 +28,12 @@ class QgsFeatureStore
/** Set crs */
void setCrs( const QgsCoordinateReferenceSystem& crs );
/** Add feature. Feature's fields will be set to pointer to the store fields.
* @param feature
* @note added in 2.1
*/
void addFeature ( const QgsFeature& feature );
/** Get features list reference */
QgsFeatureList& features();

View File

@ -58,6 +58,10 @@ class QgsRectangle
QgsPoint center() const;
//! Scale the rectangle around its center point
void scale( double, const QgsPoint *c = 0 );
void scale( double scaleFactor, double centerX, double centerY );
/** Get rectangle enlarged by buffer.
* @note added in 2.1 */
QgsRectangle buffer( double width );
//! Expand the rectangle to support zoom out scaling
//! return the intersection with the given rectangle
QgsRectangle intersect( const QgsRectangle *rect ) const;

View File

@ -40,6 +40,12 @@ class QgsSimpleFillSymbolLayerV2 : QgsFillSymbolLayerV2
QColor borderColor() const;
void setBorderColor( QColor borderColor );
virtual QColor outlineColor() const;
virtual void setOutlineColor( const QColor& color );
virtual QColor fillColor() const;
virtual void setFillColor( const QColor& color );
Qt::PenStyle borderStyle() const;
void setBorderStyle( Qt::PenStyle borderStyle );

View File

@ -42,6 +42,12 @@ class QgsSimpleMarkerSymbolLayerV2 : QgsMarkerSymbolLayerV2
double outlineWidth() const;
void setOutlineWidth( double w );
virtual QColor outlineColor() const;
virtual void setOutlineColor( const QColor& color );
virtual QColor fillColor() const;
virtual void setFillColor( const QColor& color );
QgsSymbolV2::OutputUnit outlineWidthUnit() const;
void setOutlineWidthUnit( QgsSymbolV2::OutputUnit u );

View File

@ -63,6 +63,10 @@ class QgsSymbolLayerV2
// not necessarily supported by all symbol layers...
virtual void setColor( const QColor& color );
virtual QColor color() const;
virtual void setOutlineColor( const QColor& color );
virtual QColor outlineColor() const;
virtual void setFillColor( const QColor& color );
virtual QColor fillColor() const;
virtual ~QgsSymbolLayerV2();

View File

@ -1172,14 +1172,24 @@ void QgsIdentifyResultsDialog::highlightFeature( QTreeWidgetItem *item )
if ( !featItem->feature().geometry() || featItem->feature().geometry()->wkbType() == QGis::WKBUnknown )
return;
QgsHighlight *h = new QgsHighlight( mCanvas, featItem->feature().geometry(), layer );
if ( h )
if ( vlayer )
{
h->setWidth( 2 );
QgsHighlight *h = new QgsHighlight( mCanvas, featItem->feature(), vlayer );
h->setColor( Qt::red );
h->show();
mHighlights.insert( featItem, h );
}
else
{
QgsHighlight *h = new QgsHighlight( mCanvas, featItem->feature().geometry(), layer );
if ( h )
{
h->setWidth( 2 );
h->setColor( Qt::red );
h->show();
mHighlights.insert( featItem, h );
}
}
}
void QgsIdentifyResultsDialog::zoomToFeature()

View File

@ -37,3 +37,18 @@ QgsFeatureStore::~QgsFeatureStore( )
{
}
void QgsFeatureStore::setFields( const QgsFields & fields )
{
mFields = fields;
foreach ( QgsFeature feature, mFeatures )
{
feature.setFields( &mFields );
}
}
void QgsFeatureStore::addFeature( const QgsFeature& feature )
{
QgsFeature f( feature );
f.setFields( &mFields );
mFeatures.append( f );
}

View File

@ -45,8 +45,8 @@ class CORE_EXPORT QgsFeatureStore
/** Get fields list */
QgsFields& fields() { return mFields; }
/** Set fields */
void setFields( const QgsFields & fields ) { mFields = fields; }
/** Set fields. Resets feauters fields to pointer to new internal fields. */
void setFields( const QgsFields & fields );
/** Get crs */
QgsCoordinateReferenceSystem crs() const { return mCrs; }
@ -54,6 +54,12 @@ class CORE_EXPORT QgsFeatureStore
/** Set crs */
void setCrs( const QgsCoordinateReferenceSystem& crs ) { mCrs = crs; }
/** Add feature. Feature's fields will be set to pointer to the store fields.
* @param feature
* @note added in 2.1
*/
void addFeature( const QgsFeature& feature );
/** Get features list reference */
QgsFeatureList& features() { return mFeatures; }

View File

@ -122,6 +122,11 @@ void QgsRectangle::scale( double scaleFactor, double centerX, double centerY )
ymax = centerY + newHeight / 2.0;
}
QgsRectangle QgsRectangle::buffer( double width )
{
return QgsRectangle( xmin - width, ymin - width, xmax + width, ymax + width );
}
QgsRectangle QgsRectangle::intersect( const QgsRectangle * rect ) const
{
QgsRectangle intersection = QgsRectangle();

View File

@ -82,6 +82,9 @@ class CORE_EXPORT QgsRectangle
//! Scale the rectangle around its center point
void scale( double scaleFactor, const QgsPoint *c = 0 );
void scale( double scaleFactor, double centerX, double centerY );
/** Get rectangle enlarged by buffer.
* @note added in 2.1 */
QgsRectangle buffer( double width );
//! return the intersection with the given rectangle
QgsRectangle intersect( const QgsRectangle *rect ) const;
//! returns true when rectangle intersects with other rectangle

View File

@ -65,6 +65,20 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2
QColor borderColor() const { return mBorderColor; }
void setBorderColor( QColor borderColor ) { mBorderColor = borderColor; }
/** Get outline color.
* @note added in 2.1 */
QColor outlineColor() const { return borderColor(); }
/** Set outline color.
* @note added in 2.1 */
void setOutlineColor( const QColor& color ) { setBorderColor( color ); }
/** Get fill color.
* @note added in 2.1 */
QColor fillColor() const { return color(); }
/** Set fill color.
* @note added in 2.1 */
void setFillColor( const QColor& color ) { setColor( color ); }
Qt::PenStyle borderStyle() const { return mBorderStyle; }
void setBorderStyle( Qt::PenStyle borderStyle ) { mBorderStyle = borderStyle; }

View File

@ -48,6 +48,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
// implemented from base classes
QString layerType() const;
void startRender( QgsSymbolV2RenderContext& context );
@ -73,6 +75,20 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
Qt::PenStyle outlineStyle() const { return mOutlineStyle; }
void setOutlineStyle( Qt::PenStyle outlineStyle ) { mOutlineStyle = outlineStyle; }
/** Get outline color.
* @note added in 2.1 */
QColor outlineColor() const { return borderColor(); }
/** Set outline color.
* @note added in 2.1 */
void setOutlineColor( const QColor& color ) { setBorderColor( color ); }
/** Get fill color.
* @note added in 2.1 */
QColor fillColor() const { return color(); }
/** Set fill color.
* @note added in 2.1 */
void setFillColor( const QColor& color ) { setColor( color ); }
double outlineWidth() const { return mOutlineWidth; }
void setOutlineWidth( double w ) { mOutlineWidth = w; }

View File

@ -47,8 +47,20 @@ class CORE_EXPORT QgsSymbolLayerV2
public:
// not necessarily supported by all symbol layers...
virtual void setColor( const QColor& color ) { mColor = color; }
virtual QColor color() const { return mColor; }
virtual void setColor( const QColor& color ) { mColor = color; }
/** Set outline color. Supported by marker and fill layers.
* @note added in 2.1 */
virtual void setOutlineColor( const QColor& color ) { Q_UNUSED( color ); }
/** Get outline color. Supported by marker and fill layers.
* @note added in 2.1 */
virtual QColor outlineColor() const { return QColor(); }
/** Set fill color. Supported by marker and fill layers.
* @note added in 2.1 */
virtual void setFillColor( const QColor& color ) { Q_UNUSED( color ); }
/** Get fill color. Supported by marker and fill layers.
* @note added in 2.1 */
virtual QColor fillColor() const { return QColor(); }
virtual ~QgsSymbolLayerV2() { removeDataDefinedProperties(); }

View File

@ -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"
/*!
@ -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();
@ -37,11 +45,22 @@ 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() )
@ -49,7 +68,14 @@ void QgsHighlight::init()
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();
@ -60,6 +86,7 @@ void QgsHighlight::init()
QgsHighlight::~QgsHighlight()
{
delete mGeometry;
delete mRenderer;
}
/*!
@ -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 );
}
}
}
/*!
@ -145,74 +217,96 @@ void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon )
*/
void QgsHighlight::paint( QPainter* p )
{
if ( !mGeometry )
if ( mGeometry )
{
return;
p->setPen( mPen );
p->setBrush( mBrush );
switch ( mGeometry->wkbType() )
{
case QGis::WKBPoint:
case QGis::WKBPoint25D:
{
paintPoint( p, mGeometry->asPoint() );
}
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::WKBLineString:
case QGis::WKBLineString25D:
{
paintLine( p, mGeometry->asPolyline() );
}
break;
case QGis::WKBMultiLineString:
case QGis::WKBMultiLineString25D:
{
QgsMultiPolyline m = mGeometry->asMultiPolyline();
for ( int i = 0; i < m.size(); i++ )
{
paintLine( p, m[i] );
}
}
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++ )
{
paintPolygon( p, m[i] );
}
}
break;
case QGis::WKBUnknown:
default:
return;
}
}
p->setPen( mPen );
p->setBrush( mBrush );
switch ( mGeometry->wkbType() )
else if ( mFeature.geometry() && mRenderer )
{
case QGis::WKBPoint:
case QGis::WKBPoint25D:
QgsVectorLayer *layer = vectorLayer();
if ( layer )
{
paintPoint( p, mGeometry->asPoint() );
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 );
}
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::WKBLineString:
case QGis::WKBLineString25D:
{
paintLine( p, mGeometry->asPolyline() );
}
break;
case QGis::WKBMultiLineString:
case QGis::WKBMultiLineString25D:
{
QgsMultiPolyline m = mGeometry->asMultiPolyline();
for ( int i = 0; i < m.size(); i++ )
{
paintLine( p, m[i] );
}
}
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++ )
{
paintPolygon( p, m[i] );
}
}
break;
case QGis::WKBUnknown:
default:
return;
}
}
@ -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 );
}

View File

@ -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>
@ -25,6 +27,7 @@
class QgsMapLayer;
class QgsVectorLayer;
class QgsSymbolV2;
/** A class for highlight features on the map.
*/
@ -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:
@ -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