Skip to content

Commit 68b5209

Browse files
committedDec 10, 2015
Symbol creates geometry instead of the renderer
1 parent 29a3c64 commit 68b5209

File tree

3 files changed

+573
-310
lines changed

3 files changed

+573
-310
lines changed
 

‎src/core/symbology-ng/qgsrendererv2.cpp

Lines changed: 1 addition & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -278,200 +278,7 @@ bool QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext&
278278

279279
void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
280280
{
281-
QgsSymbolV2::SymbolType symbolType = symbol->type();
282-
283-
284-
const QgsGeometry* geom = feature.constGeometry();
285-
if ( !geom || !geom->geometry() )
286-
{
287-
return;
288-
}
289-
290-
const QgsGeometry* segmentizedGeometry = geom;
291-
bool deleteSegmentizedGeometry = false;
292-
context.setGeometry( geom->geometry() );
293-
294-
//convert curve types to normal point/line/polygon ones
295-
switch ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) )
296-
{
297-
case QgsWKBTypes::CurvePolygon:
298-
case QgsWKBTypes::CircularString:
299-
case QgsWKBTypes::CompoundCurve:
300-
case QgsWKBTypes::MultiSurface:
301-
case QgsWKBTypes::MultiCurve:
302-
{
303-
QgsAbstractGeometryV2* g = geom->geometry()->segmentize();
304-
if ( !g )
305-
{
306-
return;
307-
}
308-
segmentizedGeometry = new QgsGeometry( g );
309-
deleteSegmentizedGeometry = true;
310-
break;
311-
}
312-
313-
default:
314-
break;
315-
}
316-
317-
switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
318-
{
319-
case QgsWKBTypes::Point:
320-
{
321-
if ( symbolType != QgsSymbolV2::Marker )
322-
{
323-
QgsDebugMsg( "point can be drawn only with marker symbol!" );
324-
break;
325-
}
326-
QPointF pt;
327-
_getPoint( pt, context, segmentizedGeometry->asWkb() );
328-
(( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected );
329-
if ( context.testFlag( QgsRenderContext::DrawSymbolBounds ) )
330-
{
331-
//draw debugging rect
332-
context.painter()->setPen( Qt::red );
333-
context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
334-
context.painter()->drawRect((( QgsMarkerSymbolV2* )symbol )->bounds( pt, context ) );
335-
}
336-
}
337-
break;
338-
case QgsWKBTypes::LineString:
339-
{
340-
if ( symbolType != QgsSymbolV2::Line )
341-
{
342-
QgsDebugMsg( "linestring can be drawn only with line symbol!" );
343-
break;
344-
}
345-
QPolygonF pts;
346-
_getLineString( pts, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() );
347-
(( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected );
348-
}
349-
break;
350-
case QgsWKBTypes::Polygon:
351-
{
352-
if ( symbolType != QgsSymbolV2::Fill )
353-
{
354-
QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
355-
break;
356-
}
357-
QPolygonF pts;
358-
QList<QPolygonF> holes;
359-
_getPolygon( pts, holes, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() );
360-
(( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : NULL ), &feature, context, layer, selected );
361-
}
362-
break;
363-
364-
case QgsWKBTypes::MultiPoint:
365-
{
366-
if ( symbolType != QgsSymbolV2::Marker )
367-
{
368-
QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
369-
break;
370-
}
371-
372-
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
373-
unsigned int num;
374-
wkbPtr >> num;
375-
const unsigned char* ptr = wkbPtr;
376-
QPointF pt;
377-
378-
for ( unsigned int i = 0; i < num; ++i )
379-
{
380-
ptr = QgsConstWkbPtr( _getPoint( pt, context, ptr ) );
381-
(( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected );
382-
}
383-
}
384-
break;
385-
386-
case QgsWKBTypes::MultiCurve:
387-
case QgsWKBTypes::MultiLineString:
388-
{
389-
if ( symbolType != QgsSymbolV2::Line )
390-
{
391-
QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
392-
break;
393-
}
394-
395-
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
396-
unsigned int num;
397-
wkbPtr >> num;
398-
const unsigned char* ptr = wkbPtr;
399-
QPolygonF pts;
400-
401-
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
402-
403-
for ( unsigned int i = 0; i < num; ++i )
404-
{
405-
if ( geomCollection )
406-
{
407-
context.setGeometry( geomCollection->geometryN( i ) );
408-
}
409-
ptr = QgsConstWkbPtr( _getLineString( pts, context, ptr, symbol->clipFeaturesToExtent() ) );
410-
(( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected );
411-
}
412-
}
413-
break;
414-
415-
case QgsWKBTypes::MultiSurface:
416-
case QgsWKBTypes::MultiPolygon:
417-
{
418-
if ( symbolType != QgsSymbolV2::Fill )
419-
{
420-
QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
421-
break;
422-
}
423-
424-
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
425-
unsigned int num;
426-
wkbPtr >> num;
427-
const unsigned char* ptr = wkbPtr;
428-
QPolygonF pts;
429-
QList<QPolygonF> holes;
430-
431-
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
432-
433-
for ( unsigned int i = 0; i < num; ++i )
434-
{
435-
if ( geomCollection )
436-
{
437-
context.setGeometry( geomCollection->geometryN( i ) );
438-
}
439-
ptr = _getPolygon( pts, holes, context, ptr, symbol->clipFeaturesToExtent() );
440-
(( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : NULL ), &feature, context, layer, selected );
441-
}
442-
break;
443-
}
444-
default:
445-
QgsDebugMsg( QString( "feature %1: unsupported wkb type 0x%2 for rendering" ).arg( feature.id() ).arg( geom->wkbType(), 0, 16 ) );
446-
}
447-
448-
if ( drawVertexMarker )
449-
{
450-
const QgsCoordinateTransform* ct = context.coordinateTransform();
451-
const QgsMapToPixel& mtp = context.mapToPixel();
452-
453-
QgsPointV2 vertexPoint;
454-
QgsVertexId vertexId;
455-
double x, y, z;
456-
QPointF mapPoint;
457-
while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
458-
{
459-
//transform
460-
x = vertexPoint.x(); y = vertexPoint.y(); z = vertexPoint.z();
461-
if ( ct )
462-
{
463-
ct->transformInPlace( x, y, z );
464-
}
465-
mapPoint.setX( x ); mapPoint.setY( y );
466-
mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
467-
renderVertexMarker( mapPoint, context );
468-
}
469-
}
470-
471-
if ( deleteSegmentizedGeometry )
472-
{
473-
delete segmentizedGeometry;
474-
}
281+
symbol->renderFeature( feature, context, layer, selected, drawVertexMarker, mCurrentVertexMarkerType, mCurrentVertexMarkerSize );
475282
}
476283

477284
QString QgsFeatureRendererV2::dump() const

‎src/core/symbology-ng/qgssymbolv2.cpp

Lines changed: 556 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030

3131
#include "qgsdatadefined.h"
3232

33+
#include "qgsgeometry.h"
34+
#include "qgswkbptr.h"
35+
#include "qgsgeometrycollectionv2.h"
36+
#include "qgsclipper.h"
37+
3338
#include <QColor>
3439
#include <QImage>
3540
#include <QPainter>
@@ -90,19 +95,163 @@ QgsSymbolV2::QgsSymbolV2( SymbolType type, const QgsSymbolLayerV2List& layers )
9095
{
9196
mLayers.removeAt( i-- );
9297
}
93-
else if ( !isSymbolLayerCompatible( mLayers[i]->type() ) )
98+
else if ( !mLayers[i]->isCompatibleWithSymbol( this ) )
9499
{
95100
delete mLayers[i];
96101
mLayers.removeAt( i-- );
97102
}
98103
}
99104
}
100105

106+
const unsigned char* QgsSymbolV2::_getPoint( QPointF& pt, QgsRenderContext& context, const unsigned char* wkb )
107+
{
108+
QgsConstWkbPtr wkbPtr( wkb + 1 );
109+
unsigned int wkbType;
110+
wkbPtr >> wkbType >> pt.rx() >> pt.ry();
111+
112+
if (( QgsWKBTypes::Type )wkbType == QgsWKBTypes::Point25D || ( QgsWKBTypes::Type )wkbType == QgsWKBTypes::PointZ )
113+
wkbPtr += sizeof( double );
114+
115+
if ( context.coordinateTransform() )
116+
{
117+
double z = 0; // dummy variable for coordiante transform
118+
context.coordinateTransform()->transformInPlace( pt.rx(), pt.ry(), z );
119+
}
120+
121+
context.mapToPixel().transformInPlace( pt.rx(), pt.ry() );
122+
123+
return wkbPtr;
124+
}
125+
126+
const unsigned char* QgsSymbolV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, const unsigned char* wkb, bool clipToExtent )
127+
{
128+
QgsConstWkbPtr wkbPtr( wkb + 1 );
129+
unsigned int wkbType, nPoints;
130+
wkbPtr >> wkbType >> nPoints;
131+
132+
bool hasZValue = QgsWKBTypes::hasZ(( QgsWKBTypes::Type )wkbType );
133+
bool hasMValue = QgsWKBTypes::hasM(( QgsWKBTypes::Type )wkbType );
134+
135+
double x = 0.0;
136+
double y = 0.0;
137+
const QgsCoordinateTransform* ct = context.coordinateTransform();
138+
const QgsMapToPixel& mtp = context.mapToPixel();
139+
140+
//apply clipping for large lines to achieve a better rendering performance
141+
if ( clipToExtent && nPoints > 1 )
142+
{
143+
const QgsRectangle& e = context.extent();
144+
double cw = e.width() / 10; double ch = e.height() / 10;
145+
QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
146+
wkbPtr = QgsConstWkbPtr( QgsClipper::clippedLineWKB( wkb, clipRect, pts ) );
147+
}
148+
else
149+
{
150+
pts.resize( nPoints );
151+
152+
QPointF* ptr = pts.data();
153+
for ( unsigned int i = 0; i < nPoints; ++i, ++ptr )
154+
{
155+
wkbPtr >> x >> y;
156+
if ( hasZValue )
157+
wkbPtr += sizeof( double );
158+
if ( hasMValue )
159+
wkbPtr += sizeof( double );
160+
161+
*ptr = QPointF( x, y );
162+
}
163+
}
164+
165+
//transform the QPolygonF to screen coordinates
166+
if ( ct )
167+
{
168+
ct->transformPolygon( pts );
169+
}
170+
171+
QPointF* ptr = pts.data();
172+
for ( int i = 0; i < pts.size(); ++i, ++ptr )
173+
{
174+
mtp.transformInPlace( ptr->rx(), ptr->ry() );
175+
}
176+
177+
return wkbPtr;
178+
}
179+
180+
const unsigned char* QgsSymbolV2::_getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, const unsigned char* wkb, bool clipToExtent )
181+
{
182+
QgsConstWkbPtr wkbPtr( wkb + 1 );
183+
184+
unsigned int wkbType, numRings;
185+
wkbPtr >> wkbType >> numRings;
186+
187+
if ( numRings == 0 ) // sanity check for zero rings in polygon
188+
return wkbPtr;
189+
190+
bool hasZValue = QgsWKBTypes::hasZ(( QgsWKBTypes::Type )wkbType );
191+
bool hasMValue = QgsWKBTypes::hasM(( QgsWKBTypes::Type )wkbType );
192+
193+
double x, y;
194+
holes.clear();
195+
196+
const QgsCoordinateTransform* ct = context.coordinateTransform();
197+
const QgsMapToPixel& mtp = context.mapToPixel();
198+
const QgsRectangle& e = context.extent();
199+
double cw = e.width() / 10; double ch = e.height() / 10;
200+
QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
201+
202+
for ( unsigned int idx = 0; idx < numRings; idx++ )
203+
{
204+
unsigned int nPoints;
205+
wkbPtr >> nPoints;
206+
207+
QPolygonF poly( nPoints );
208+
209+
// Extract the points from the WKB and store in a pair of vectors.
210+
QPointF* ptr = poly.data();
211+
for ( unsigned int jdx = 0; jdx < nPoints; ++jdx, ++ptr )
212+
{
213+
wkbPtr >> x >> y;
214+
if ( hasZValue )
215+
wkbPtr += sizeof( double );
216+
if ( hasMValue )
217+
wkbPtr += sizeof( double );
218+
219+
*ptr = QPointF( x, y );
220+
}
221+
222+
if ( nPoints < 1 )
223+
continue;
224+
225+
//clip close to view extent, if needed
226+
QRectF ptsRect = poly.boundingRect();
227+
if ( clipToExtent && !context.extent().contains( ptsRect ) ) QgsClipper::trimPolygon( poly, clipRect );
228+
229+
//transform the QPolygonF to screen coordinates
230+
if ( ct )
231+
{
232+
ct->transformPolygon( poly );
233+
}
234+
235+
236+
ptr = poly.data();
237+
for ( int i = 0; i < poly.size(); ++i, ++ptr )
238+
{
239+
mtp.transformInPlace( ptr->rx(), ptr->ry() );
240+
}
241+
242+
if ( idx == 0 )
243+
pts = poly;
244+
else
245+
holes.append( poly );
246+
}
247+
248+
return wkbPtr;
249+
}
250+
101251
QgsSymbolV2::~QgsSymbolV2()
102252
{
103253
// delete all symbol layers (we own them, so it's okay)
104-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
105-
delete *it;
254+
qDeleteAll( mLayers );
106255
}
107256

108257
QgsSymbolV2::OutputUnit QgsSymbolV2::outputUnit() const
@@ -217,28 +366,25 @@ QgsSymbolV2* QgsSymbolV2::defaultSymbol( QGis::GeometryType geomType )
217366

218367
QgsSymbolLayerV2* QgsSymbolV2::symbolLayer( int layer )
219368
{
220-
if ( layer < 0 || layer >= mLayers.count() )
221-
return NULL;
222-
223-
return mLayers[layer];
369+
return mLayers.value( layer );
224370
}
225371

226372

227-
bool QgsSymbolV2::isSymbolLayerCompatible( SymbolType t )
373+
bool QgsSymbolV2::isSymbolLayerCompatible( SymbolType layerType )
228374
{
229375
// fill symbol can contain also line symbol layers for drawing of outlines
230-
if ( mType == Fill && t == Line )
376+
if ( mType == Fill && layerType == Line )
231377
return true;
232378

233-
return mType == t;
379+
return mType == layerType;
234380
}
235381

236382

237383
bool QgsSymbolV2::insertSymbolLayer( int index, QgsSymbolLayerV2* layer )
238384
{
239385
if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
240386
return false;
241-
if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
387+
if ( layer == NULL || !layer->isCompatibleWithSymbol( this ) )
242388
return false;
243389

244390
mLayers.insert( index, layer );
@@ -248,7 +394,7 @@ bool QgsSymbolV2::insertSymbolLayer( int index, QgsSymbolLayerV2* layer )
248394

249395
bool QgsSymbolV2::appendSymbolLayer( QgsSymbolLayerV2* layer )
250396
{
251-
if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
397+
if ( layer == NULL || !layer->isCompatibleWithSymbol( this ) )
252398
return false;
253399

254400
mLayers.append( layer );
@@ -280,7 +426,7 @@ bool QgsSymbolV2::changeSymbolLayer( int index, QgsSymbolLayerV2* layer )
280426
{
281427
if ( index < 0 || index >= mLayers.count() )
282428
return false;
283-
if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
429+
if ( layer == NULL || !layer->isCompatibleWithSymbol( this ) )
284430
return false;
285431

286432
delete mLayers[index]; // first delete the original layer
@@ -294,26 +440,26 @@ void QgsSymbolV2::startRender( QgsRenderContext& context, const QgsFields* field
294440
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, fields, mapUnitScale() );
295441

296442

297-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
298-
( *it )->startRender( symbolContext );
443+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
444+
layer->startRender( symbolContext );
299445
}
300446

301447
void QgsSymbolV2::stopRender( QgsRenderContext& context )
302448
{
303449
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() );
304450

305-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
306-
( *it )->stopRender( symbolContext );
451+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
452+
layer->stopRender( symbolContext );
307453

308454
mLayer = NULL;
309455
}
310456

311457
void QgsSymbolV2::setColor( const QColor& color )
312458
{
313-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
459+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
314460
{
315-
if ( !( *it )->isLocked() )
316-
( *it )->setColor( color );
461+
if ( !layer->isLocked() )
462+
layer->setColor( color );
317463
}
318464
}
319465

@@ -334,22 +480,25 @@ void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size, QgsRenderConte
334480
context.setForceVectorOutput( true );
335481
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() );
336482

337-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
483+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
338484
{
339-
if ( mType == Fill && ( *it )->type() == Line )
485+
if ( mType == Fill && layer->type() == Line )
340486
{
341487
// line symbol layer would normally draw just a line
342488
// so we override this case to force it to draw a polygon outline
343-
QgsLineSymbolLayerV2* lsl = ( QgsLineSymbolLayerV2* ) * it;
489+
QgsLineSymbolLayerV2* lsl = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
344490

345-
// from QgsFillSymbolLayerV2::drawPreviewIcon()
346-
QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
347-
lsl->startRender( symbolContext );
348-
lsl->renderPolygonOutline( poly, NULL, symbolContext );
349-
lsl->stopRender( symbolContext );
491+
if ( lsl )
492+
{
493+
// from QgsFillSymbolLayerV2::drawPreviewIcon()
494+
QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
495+
lsl->startRender( symbolContext );
496+
lsl->renderPolygonOutline( poly, NULL, symbolContext );
497+
lsl->stopRender( symbolContext );
498+
}
350499
}
351500
else
352-
( *it )->drawPreviewIcon( symbolContext, size );
501+
layer->drawPreviewIcon( symbolContext, size );
353502
}
354503
}
355504

@@ -476,6 +625,68 @@ QgsSymbolLayerV2List QgsSymbolV2::cloneLayers() const
476625
return lst;
477626
}
478627

628+
void QgsSymbolV2::renderUsingLayer( QgsSymbolLayerV2* layer, QgsSymbolV2RenderContext& context )
629+
{
630+
static QPointF nullPoint;
631+
static QPolygonF nullLine;
632+
static QList<QPolygonF> nullRings;
633+
634+
635+
QgsPaintEffect* effect = layer->paintEffect();
636+
if ( effect && effect->enabled() )
637+
{
638+
QPainter* p = context.renderContext().painter();
639+
p->save();
640+
641+
effect->begin( context.renderContext() );
642+
switch ( layer->type() )
643+
{
644+
case Fill:
645+
static_cast<QgsFillSymbolLayerV2*>( layer )->renderPolygon( nullLine, &nullRings, context );
646+
break;
647+
648+
case Line:
649+
static_cast<QgsLineSymbolLayerV2*>( layer )->renderPolyline( nullLine, context );
650+
break;
651+
652+
case Marker:
653+
static_cast<QgsMarkerSymbolLayerV2*>( layer )->renderPoint( nullPoint, context );
654+
break;
655+
656+
case Hybrid:
657+
Q_ASSERT( false );
658+
// Layers should only be registered as accepting hybrid input but always return a defined output
659+
break;
660+
}
661+
662+
effect->end( context.renderContext() );
663+
664+
p->restore();
665+
}
666+
else
667+
{
668+
switch ( layer->type() )
669+
{
670+
case Fill:
671+
static_cast<QgsFillSymbolLayerV2*>( layer )->renderPolygon( nullLine, &nullRings, context );
672+
break;
673+
674+
case Line:
675+
static_cast<QgsLineSymbolLayerV2*>( layer )->renderPolyline( nullLine, context );
676+
break;
677+
678+
case Marker:
679+
static_cast<QgsMarkerSymbolLayerV2*>( layer )->renderPoint( nullPoint, context );
680+
break;
681+
682+
case Hybrid:
683+
Q_ASSERT( false );
684+
// Layers should only be registered as accepting hybrid input but always return a defined output
685+
break;
686+
}
687+
}
688+
}
689+
479690
QSet<QString> QgsSymbolV2::usedAttributes() const
480691
{
481692
QSet<QString> attributes;
@@ -500,13 +711,220 @@ bool QgsSymbolV2::hasDataDefinedProperties() const
500711
return false;
501712
}
502713

714+
void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
715+
{
716+
const QgsGeometry* geom = feature.constGeometry();
717+
if ( !geom || !geom->geometry() )
718+
{
719+
return;
720+
}
721+
722+
const QgsGeometry* segmentizedGeometry = geom;
723+
bool deleteSegmentizedGeometry = false;
724+
context.setGeometry( geom->geometry() );
725+
726+
//convert curve types to normal point/line/polygon ones
727+
switch ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) )
728+
{
729+
case QgsWKBTypes::CurvePolygon:
730+
case QgsWKBTypes::CircularString:
731+
case QgsWKBTypes::CompoundCurve:
732+
case QgsWKBTypes::MultiSurface:
733+
case QgsWKBTypes::MultiCurve:
734+
{
735+
QgsAbstractGeometryV2* g = geom->geometry()->segmentize();
736+
if ( !g )
737+
{
738+
return;
739+
}
740+
segmentizedGeometry = new QgsGeometry( g );
741+
deleteSegmentizedGeometry = true;
742+
break;
743+
}
744+
745+
default:
746+
break;
747+
}
748+
749+
switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
750+
{
751+
case QgsWKBTypes::Point:
752+
{
753+
QPointF pt;
754+
if ( mType != QgsSymbolV2::Marker )
755+
{
756+
QgsDebugMsg( "point can be drawn only with marker symbol!" );
757+
break;
758+
}
759+
_getPoint( pt, context, segmentizedGeometry->asWkb() );
760+
( static_cast<QgsMarkerSymbolV2*>( this ) )->renderPoint( pt, &feature, context, layer, selected );
761+
if ( context.testFlag( QgsRenderContext::DrawSymbolBounds ) )
762+
{
763+
//draw debugging rect
764+
context.painter()->setPen( Qt::red );
765+
context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
766+
context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context ) );
767+
}
768+
}
769+
break;
770+
case QgsWKBTypes::LineString:
771+
{
772+
QPolygonF pts;
773+
if ( mType != QgsSymbolV2::Line )
774+
{
775+
QgsDebugMsg( "linestring can be drawn only with line symbol!" );
776+
break;
777+
}
778+
_getLineString( pts, context, segmentizedGeometry->asWkb(), clipFeaturesToExtent() );
779+
static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
780+
}
781+
break;
782+
case QgsWKBTypes::Polygon:
783+
{
784+
QPolygonF pts;
785+
QList<QPolygonF> holes;
786+
if ( mType != QgsSymbolV2::Fill )
787+
{
788+
QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
789+
break;
790+
}
791+
_getPolygon( pts, holes, context, segmentizedGeometry->asWkb(), clipFeaturesToExtent() );
792+
static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : NULL ), &feature, context, layer, selected );
793+
}
794+
break;
795+
796+
case QgsWKBTypes::MultiPoint:
797+
{
798+
QPointF pt;
799+
800+
if ( mType != QgsSymbolV2::Marker )
801+
{
802+
QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
803+
break;
804+
}
805+
806+
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
807+
unsigned int num;
808+
wkbPtr >> num;
809+
const unsigned char* ptr = wkbPtr;
810+
811+
for ( unsigned int i = 0; i < num; ++i )
812+
{
813+
ptr = QgsConstWkbPtr( _getPoint( pt, context, ptr ) );
814+
static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
815+
}
816+
}
817+
break;
818+
819+
case QgsWKBTypes::MultiCurve:
820+
case QgsWKBTypes::MultiLineString:
821+
{
822+
QPolygonF pts;
823+
824+
if ( mType != QgsSymbolV2::Line )
825+
{
826+
QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
827+
break;
828+
}
829+
830+
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
831+
unsigned int num;
832+
wkbPtr >> num;
833+
const unsigned char* ptr = wkbPtr;
834+
835+
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
836+
837+
for ( unsigned int i = 0; i < num; ++i )
838+
{
839+
if ( geomCollection )
840+
{
841+
context.setGeometry( geomCollection->geometryN( i ) );
842+
}
843+
ptr = QgsConstWkbPtr( _getLineString( pts, context, ptr, clipFeaturesToExtent() ) );
844+
static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
845+
}
846+
}
847+
break;
848+
849+
case QgsWKBTypes::MultiSurface:
850+
case QgsWKBTypes::MultiPolygon:
851+
{
852+
if ( mType != QgsSymbolV2::Fill )
853+
{
854+
QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
855+
break;
856+
}
857+
858+
QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) );
859+
unsigned int num;
860+
wkbPtr >> num;
861+
const unsigned char* ptr = wkbPtr;
862+
863+
QPolygonF pts;
864+
QList<QPolygonF> holes;
865+
866+
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
867+
868+
for ( unsigned int i = 0; i < num; ++i )
869+
{
870+
if ( geomCollection )
871+
{
872+
context.setGeometry( geomCollection->geometryN( i ) );
873+
}
874+
ptr = _getPolygon( pts, holes, context, ptr, clipFeaturesToExtent() );
875+
static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : NULL ), &feature, context, layer, selected );
876+
}
877+
break;
878+
}
879+
default:
880+
QgsDebugMsg( QString( "feature %1: unsupported wkb type 0x%2 for rendering" ).arg( feature.id() ).arg( geom->wkbType(), 0, 16 ) );
881+
}
882+
883+
if ( drawVertexMarker )
884+
{
885+
const QgsCoordinateTransform* ct = context.coordinateTransform();
886+
const QgsMapToPixel& mtp = context.mapToPixel();
887+
888+
QgsPointV2 vertexPoint;
889+
QgsVertexId vertexId;
890+
double x, y, z;
891+
QPointF mapPoint;
892+
while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
893+
{
894+
//transform
895+
x = vertexPoint.x(); y = vertexPoint.y(); z = vertexPoint.z();
896+
if ( ct )
897+
{
898+
ct->transformInPlace( x, y, z );
899+
}
900+
mapPoint.setX( x ); mapPoint.setY( y );
901+
mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
902+
QgsVectorLayer::drawVertexMarker( mapPoint.x(), mapPoint.y(), *context.painter(),
903+
( QgsVectorLayer::VertexMarkerType ) currentVertexMarkerType,
904+
currentVertexMarkerSize );
905+
}
906+
}
907+
908+
if ( deleteSegmentizedGeometry )
909+
{
910+
delete segmentizedGeometry;
911+
}
912+
}
913+
503914
////////////////////
504915

505916

506917
QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected, int renderHints, const QgsFeature* f, const QgsFields* fields, const QgsMapUnitScale& mapUnitScale )
507-
: mRenderContext( c ), mOutputUnit( u ), mMapUnitScale( mapUnitScale ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints ), mFeature( f ), mFields( fields )
918+
: mRenderContext( c ),
919+
mOutputUnit( u ),
920+
mMapUnitScale( mapUnitScale ),
921+
mAlpha( alpha ),
922+
mSelected( selected ),
923+
mRenderHints( renderHints ),
924+
mFeature( f ),
925+
mFields( fields ),
926+
mExpressionContext( c.expressionContext() )
508927
{
509-
510928
}
511929

512930
QgsSymbolV2RenderContext::~QgsSymbolV2RenderContext()
@@ -587,10 +1005,11 @@ void QgsMarkerSymbolV2::setAngle( double ang )
5871005
{
5881006
double origAngle = angle();
5891007
double angleDiff = ang - origAngle;
590-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1008+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
5911009
{
592-
QgsMarkerSymbolLayerV2* layer = ( QgsMarkerSymbolLayerV2* ) * it;
593-
layer->setAngle( layer->angle() + angleDiff );
1010+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1011+
if ( markerLayer )
1012+
markerLayer->setAngle( markerLayer->angle() + angleDiff );
5941013
}
5951014
}
5961015

@@ -608,34 +1027,40 @@ double QgsMarkerSymbolV2::angle() const
6081027

6091028
void QgsMarkerSymbolV2::setLineAngle( double lineAng )
6101029
{
611-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1030+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
6121031
{
613-
QgsMarkerSymbolLayerV2* layer = ( QgsMarkerSymbolLayerV2* ) * it;
614-
layer->setLineAngle( lineAng );
1032+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1033+
1034+
if ( markerLayer )
1035+
markerLayer->setLineAngle( lineAng );
6151036
}
6161037
}
6171038

6181039
void QgsMarkerSymbolV2::setDataDefinedAngle( const QgsDataDefined& dd )
6191040
{
6201041
const double symbolRotation = angle();
6211042

622-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1043+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
6231044
{
624-
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2 *>( *it );
625-
if ( dd.hasDefaultValues() )
626-
{
627-
layer->removeDataDefinedProperty( "angle" );
628-
}
629-
else
1045+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1046+
1047+
if ( markerLayer )
6301048
{
631-
if ( qgsDoubleNear( layer->angle(), symbolRotation ) )
1049+
if ( dd.hasDefaultValues() )
6321050
{
633-
layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1051+
layer->removeDataDefinedProperty( "angle" );
6341052
}
6351053
else
6361054
{
637-
QgsDataDefined* rotatedDD = rotateWholeSymbol( layer->angle() - symbolRotation, dd );
638-
layer->setDataDefinedProperty( "angle", rotatedDD );
1055+
if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1056+
{
1057+
layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1058+
}
1059+
else
1060+
{
1061+
QgsDataDefined* rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, dd );
1062+
layer->setDataDefinedProperty( "angle", rotatedDD );
1063+
}
6391064
}
6401065
}
6411066
}
@@ -687,20 +1112,20 @@ void QgsMarkerSymbolV2::setSize( double s )
6871112
{
6881113
double origSize = size();
6891114

690-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1115+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
6911116
{
692-
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
693-
if ( layer->size() == origSize )
694-
layer->setSize( s );
1117+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1118+
if ( markerLayer->size() == origSize )
1119+
markerLayer->setSize( s );
6951120
else if ( origSize != 0 )
6961121
{
6971122
// proportionally scale size
698-
layer->setSize( layer->size() * s / origSize );
1123+
markerLayer->setSize( markerLayer->size() * s / origSize );
6991124
}
7001125
// also scale offset to maintain relative position
701-
if ( origSize != 0 && ( layer->offset().x() || layer->offset().y() ) )
702-
layer->setOffset( QPointF( layer->offset().x() * s / origSize,
703-
layer->offset().y() * s / origSize ) );
1126+
if ( origSize != 0 && ( markerLayer->offset().x() || markerLayer->offset().y() ) )
1127+
markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1128+
markerLayer->offset().y() * s / origSize ) );
7041129
}
7051130
}
7061131

@@ -722,31 +1147,31 @@ void QgsMarkerSymbolV2::setDataDefinedSize( const QgsDataDefined &dd )
7221147
{
7231148
const double symbolSize = size();
7241149

725-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1150+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
7261151
{
727-
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2 *>( *it );
1152+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2 *>( layer );
7281153

7291154
if ( dd.hasDefaultValues() )
7301155
{
731-
layer->removeDataDefinedProperty( "size" );
732-
layer->removeDataDefinedProperty( "offset" );
1156+
markerLayer->removeDataDefinedProperty( "size" );
1157+
markerLayer->removeDataDefinedProperty( "offset" );
7331158
}
7341159
else
7351160
{
736-
if ( symbolSize == 0 || qgsDoubleNear( layer->size(), symbolSize ) )
1161+
if ( symbolSize == 0 || qgsDoubleNear( markerLayer->size(), symbolSize ) )
7371162
{
738-
layer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
1163+
markerLayer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
7391164
}
7401165
else
7411166
{
742-
layer->setDataDefinedProperty( "size", scaleWholeSymbol( layer->size() / symbolSize, dd ) );
1167+
markerLayer->setDataDefinedProperty( "size", scaleWholeSymbol( markerLayer->size() / symbolSize, dd ) );
7431168
}
7441169

745-
if ( layer->offset().x() || layer->offset().y() )
1170+
if ( markerLayer->offset().x() || markerLayer->offset().y() )
7461171
{
747-
layer->setDataDefinedProperty( "offset", scaleWholeSymbol(
748-
layer->offset().x() / symbolSize,
749-
layer->offset().y() / symbolSize, dd ) );
1172+
markerLayer->setDataDefinedProperty( "offset", scaleWholeSymbol(
1173+
markerLayer->offset().x() / symbolSize,
1174+
markerLayer->offset().y() / symbolSize, dd ) );
7501175
}
7511176
}
7521177
}
@@ -805,10 +1230,11 @@ QgsDataDefined QgsMarkerSymbolV2::dataDefinedSize() const
8051230

8061231
void QgsMarkerSymbolV2::setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod )
8071232
{
808-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1233+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
8091234
{
810-
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
811-
layer->setScaleMethod( scaleMethod );
1235+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1236+
if ( markerLayer )
1237+
markerLayer->setScaleMethod( scaleMethod );
8121238
}
8131239
}
8141240

@@ -860,9 +1286,12 @@ void QgsMarkerSymbolV2::renderPoint( const QPointF& point, const QgsFeature* f,
8601286
return;
8611287
}
8621288

863-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1289+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
8641290
{
865-
renderPointUsingLayer(( QgsMarkerSymbolLayerV2* ) * it, point, symbolContext );
1291+
QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1292+
1293+
if ( markerLayer )
1294+
renderPointUsingLayer( markerLayer, point, symbolContext );
8661295
}
8671296
}
8681297

@@ -905,33 +1334,41 @@ void QgsLineSymbolV2::setWidth( double w )
9051334
{
9061335
double origWidth = width();
9071336

908-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1337+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
9091338
{
910-
QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
911-
if ( layer->width() == origWidth )
912-
{
913-
layer->setWidth( w );
914-
}
915-
else if ( origWidth != 0 )
1339+
QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1340+
1341+
if ( lineLayer )
9161342
{
917-
// proportionally scale the width
918-
layer->setWidth( layer->width() * w / origWidth );
1343+
if ( lineLayer->width() == origWidth )
1344+
{
1345+
lineLayer->setWidth( w );
1346+
}
1347+
else if ( origWidth != 0 )
1348+
{
1349+
// proportionally scale the width
1350+
lineLayer->setWidth( lineLayer->width() * w / origWidth );
1351+
}
1352+
// also scale offset to maintain relative position
1353+
if ( origWidth != 0 && lineLayer->offset() )
1354+
lineLayer->setOffset( lineLayer->offset() * w / origWidth );
9191355
}
920-
// also scale offset to maintain relative position
921-
if ( origWidth != 0 && layer->offset() )
922-
layer->setOffset( layer->offset() * w / origWidth );
9231356
}
9241357
}
9251358

9261359
double QgsLineSymbolV2::width() const
9271360
{
9281361
double maxWidth = 0;
929-
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1362+
1363+
Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
9301364
{
931-
const QgsLineSymbolLayerV2* layer = ( const QgsLineSymbolLayerV2* ) * it;
932-
double width = layer->width();
933-
if ( width > maxWidth )
934-
maxWidth = width;
1365+
const QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1366+
if ( lineLayer )
1367+
{
1368+
double width = lineLayer->width();
1369+
if ( width > maxWidth )
1370+
maxWidth = width;
1371+
}
9351372
}
9361373
return maxWidth;
9371374
}
@@ -940,29 +1377,32 @@ void QgsLineSymbolV2::setDataDefinedWidth( const QgsDataDefined& dd )
9401377
{
9411378
const double symbolWidth = width();
9421379

943-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1380+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
9441381
{
945-
QgsLineSymbolLayerV2* layer = static_cast<QgsLineSymbolLayerV2*>( *it );
1382+
QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
9461383

947-
if ( dd.hasDefaultValues() )
948-
{
949-
layer->removeDataDefinedProperty( "width" );
950-
layer->removeDataDefinedProperty( "offset" );
951-
}
952-
else
1384+
if ( lineLayer )
9531385
{
954-
if ( symbolWidth == 0 || qgsDoubleNear( layer->width(), symbolWidth ) )
1386+
if ( dd.hasDefaultValues() )
9551387
{
956-
layer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1388+
lineLayer->removeDataDefinedProperty( "width" );
1389+
lineLayer->removeDataDefinedProperty( "offset" );
9571390
}
9581391
else
9591392
{
960-
layer->setDataDefinedProperty( "width", scaleWholeSymbol( layer->width() / symbolWidth, dd ) );
961-
}
962-
963-
if ( layer->offset() )
964-
{
965-
layer->setDataDefinedProperty( "offset", scaleWholeSymbol( layer->offset() / symbolWidth, dd ) );
1393+
if ( symbolWidth == 0 || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1394+
{
1395+
lineLayer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1396+
}
1397+
else
1398+
{
1399+
lineLayer->setDataDefinedProperty( "width", scaleWholeSymbol( lineLayer->width() / symbolWidth, dd ) );
1400+
}
1401+
1402+
if ( lineLayer->offset() )
1403+
{
1404+
lineLayer->setDataDefinedProperty( "offset", scaleWholeSymbol( lineLayer->offset() / symbolWidth, dd ) );
1405+
}
9661406
}
9671407
}
9681408
}
@@ -977,8 +1417,8 @@ QgsDataDefined QgsLineSymbolV2::dataDefinedWidth() const
9771417
// find the base of the "en masse" pattern
9781418
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
9791419
{
980-
const QgsLineSymbolLayerV2* layer = static_cast<const QgsLineSymbolLayerV2*>( *it );
981-
if ( layer->width() == symbolWidth && layer->getDataDefinedProperty( "width" ) )
1420+
const QgsLineSymbolLayerV2* layer = dynamic_cast<const QgsLineSymbolLayerV2*>( *it );
1421+
if ( layer && layer->width() == symbolWidth && layer->getDataDefinedProperty( "width" ) )
9821422
{
9831423
symbolDD = layer->getDataDefinedProperty( "width" );
9841424
break;
@@ -1119,11 +1559,11 @@ void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QP
11191559
effect->begin( context.renderContext() );
11201560
if ( layertype == QgsSymbolV2::Fill )
11211561
{
1122-
(( QgsFillSymbolLayerV2* )layer )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1562+
( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
11231563
}
11241564
else if ( layertype == QgsSymbolV2::Line )
11251565
{
1126-
(( QgsLineSymbolLayerV2* )layer )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
1566+
( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
11271567
}
11281568
delete translatedRings;
11291569

@@ -1134,11 +1574,11 @@ void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QP
11341574
{
11351575
if ( layertype == QgsSymbolV2::Fill )
11361576
{
1137-
(( QgsFillSymbolLayerV2* )layer )->renderPolygon( points, rings, context );
1577+
( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points, rings, context );
11381578
}
11391579
else if ( layertype == QgsSymbolV2::Line )
11401580
{
1141-
(( QgsLineSymbolLayerV2* )layer )->renderPolygonOutline( points, rings, context );
1581+
( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points, rings, context );
11421582
}
11431583
}
11441584
}
@@ -1182,10 +1622,12 @@ QgsFillSymbolV2* QgsFillSymbolV2::clone() const
11821622

11831623
void QgsFillSymbolV2::setAngle( double angle )
11841624
{
1185-
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1625+
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
11861626
{
1187-
QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
1188-
layer->setAngle( angle );
1627+
QgsFillSymbolLayerV2* fillLayer = dynamic_cast<QgsFillSymbolLayerV2*>( layer );
1628+
1629+
if ( fillLayer )
1630+
fillLayer->setAngle( angle );
11891631
}
11901632
}
11911633

‎src/core/symbology-ng/qgssymbolv2.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class QgsMarkerSymbolLayerV2;
4242
class QgsLineSymbolLayerV2;
4343
class QgsFillSymbolLayerV2;
4444
class QgsDataDefined;
45+
class QgsSymbolV2RenderContext;
4546

4647
typedef QList<QgsSymbolLayerV2*> QgsSymbolLayerV2List;
4748

@@ -69,7 +70,8 @@ class CORE_EXPORT QgsSymbolV2
6970
{
7071
Marker, //!< Marker symbol
7172
Line, //!< Line symbol
72-
Fill //!< Fill symbol
73+
Fill, //!< Fill symbol
74+
Hybrid //!< Hybrid symbol
7375
};
7476

7577
/**
@@ -226,14 +228,23 @@ class CORE_EXPORT QgsSymbolV2
226228
void setLayer( const QgsVectorLayer* layer ) { mLayer = layer; }
227229
const QgsVectorLayer* layer() const { return mLayer; }
228230

231+
void renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false, int currentVertexMarkerType = 0, int currentVertexMarkerSize = 0 );
232+
229233
protected:
230234
QgsSymbolV2( SymbolType type, const QgsSymbolLayerV2List& layers ); // can't be instantiated
231235

236+
static const unsigned char* _getPoint( QPointF& pt, QgsRenderContext& context, const unsigned char* wkb );
237+
static const unsigned char* _getLineString( QPolygonF& pts, QgsRenderContext& context, const unsigned char* wkb, bool clipToExtent = true );
238+
static const unsigned char* _getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, const unsigned char* wkb, bool clipToExtent = true );
239+
232240
QgsSymbolLayerV2List cloneLayers() const;
233241

242+
void renderUsingLayer( QgsSymbolLayerV2* layer, QgsSymbolV2RenderContext& context );
243+
234244
//! check whether a symbol layer type can be used within the symbol
235245
//! (marker-marker, line-line, fill-fill/line)
236-
bool isSymbolLayerCompatible( SymbolType t );
246+
//! @deprecated since 2.14, use QgsSymbolLayerV2::isCompatibleWithSymbol instead
247+
Q_DECL_DEPRECATED bool isSymbolLayerCompatible( SymbolType layerType );
237248

238249
SymbolType mType;
239250
QgsSymbolLayerV2List mLayers;
@@ -259,6 +270,8 @@ class CORE_EXPORT QgsSymbolV2RenderContext
259270
QgsRenderContext& renderContext() { return mRenderContext; }
260271
const QgsRenderContext& renderContext() const { return mRenderContext; }
261272

273+
const QgsExpressionContext& expressionContext() const { return mExpressionContext; }
274+
262275
/** Sets the original value variable value for data defined symbology
263276
* @param value value for original value variable. This usually represents the symbol property value
264277
* before any data defined overrides have been applied.
@@ -308,6 +321,7 @@ class CORE_EXPORT QgsSymbolV2RenderContext
308321
int mRenderHints;
309322
const QgsFeature* mFeature; //current feature
310323
const QgsFields* mFields;
324+
QgsExpressionContext mExpressionContext;
311325
};
312326

313327

0 commit comments

Comments
 (0)
Please sign in to comment.