Skip to content

Commit 1e7a554

Browse files
committedNov 26, 2011
Support multiple matching rules per feature, always using symbol levels
1 parent 898604d commit 1e7a554

File tree

5 files changed

+152
-18
lines changed

5 files changed

+152
-18
lines changed
 

‎src/core/qgsvectorlayer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,8 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
784784
#endif //Q_WS_MAC
785785
}
786786

787+
stopRendererV2( rendererContext, NULL );
788+
787789
#ifndef Q_WS_MAC
788790
QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
789791
#endif

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ void QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext&
187187
if ( symbol == NULL )
188188
return;
189189

190+
renderFeatureWithSymbol( feature, symbol, context, layer, selected, drawVertexMarker );
191+
}
192+
193+
void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
194+
{
190195
QgsSymbolV2::SymbolType symbolType = symbol->type();
191196

192197
QgsGeometry* geom = feature.geometry();

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ class CORE_EXPORT QgsFeatureRendererV2
107107
protected:
108108
QgsFeatureRendererV2( QString type );
109109

110+
void renderFeatureWithSymbol( QgsFeature& feature,
111+
QgsSymbolV2* symbol,
112+
QgsRenderContext& context,
113+
int layer,
114+
bool selected,
115+
bool drawVertexMarker );
116+
110117
//! render editing vertex marker at specified point
111118
void renderVertexMarker( QPointF& pt, QgsRenderContext& context );
112119
//! render editing vertex marker for a polyline

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

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,9 @@ QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
125125
}
126126

127127

128-
QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& feature )
128+
QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& )
129129
{
130-
if ( ! usingFirstRule() )
131-
return mCurrentSymbol;
132-
133-
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
134-
{
135-
Rule* rule = *it;
136-
137-
if ( rule->isFilterOK( feature ) )
138-
{
139-
return rule->symbol(); //works with levels but takes only first rule
140-
}
141-
}
130+
// not used at all
142131
return 0;
143132
}
144133

@@ -148,16 +137,37 @@ void QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature,
148137
bool selected,
149138
bool drawVertexMarker )
150139
{
140+
141+
// TODO: selected features, vertex markers
142+
143+
// check each active rule
144+
QgsFeature* featPtr = NULL;
151145
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
152146
{
153147
Rule* rule = *it;
148+
// if matching: add rendering job to queue
154149
if ( rule->isFilterOK( feature ) )
155150
{
156-
mCurrentSymbol = rule->symbol();
157-
// will ask for mCurrentSymbol
158-
QgsFeatureRendererV2::renderFeature( feature, context, layer, selected, drawVertexMarker );
151+
//QgsDebugMsg(QString("matching fid %1").arg(feature.id()));
152+
// make a copy of the feature if not yet exists
153+
if ( !featPtr )
154+
{
155+
featPtr = new QgsFeature( feature );
156+
mCurrentFeatures.append( featPtr );
157+
}
158+
159+
// create job for this feature and this symbol, add to list of jobs
160+
//RenderJob* job = new RenderJob( featPtr, rule->symbol() );
161+
//mRenderJobs.append( job );
162+
// add job to the queue: each symbol's zLevel must be added
163+
foreach( int normZLevel, rule->mSymbolNormZLevels )
164+
{
165+
//QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
166+
mRenderQueue.levels[normZLevel].jobs.append( new RenderJob( featPtr, rule->symbol() ) );
167+
}
159168
}
160169
}
170+
161171
}
162172

163173

@@ -166,6 +176,7 @@ void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVe
166176
double currentScale = context.rendererScale();
167177
// filter out rules which are not compatible with this scale
168178

179+
// build temporary list of active rules (usable with this scale)
169180
mCurrentRules.clear();
170181
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
171182
{
@@ -176,18 +187,98 @@ void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVe
176187

177188
QgsFieldMap pendingFields = vlayer->pendingFields();
178189

179-
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
190+
QSet<int> symbolZLevelsSet;
191+
192+
QList<Rule*>::iterator it;
193+
for ( it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
180194
{
181195
Rule* rule = *it;
182196
QgsExpression* exp = rule->filter();
183197
if ( exp )
184198
exp->prepare( pendingFields );
185-
rule->symbol()->startRender( context, vlayer );
199+
200+
// prepare symbol
201+
QgsSymbolV2* s = rule->symbol();
202+
s->startRender( context, vlayer );
203+
204+
QgsDebugMsg( "rule " + rule->dump() );
205+
206+
// find out which Z-levels are used
207+
for ( int i = 0; i < s->symbolLayerCount(); i++ )
208+
{
209+
symbolZLevelsSet.insert( s->symbolLayer( i )->renderingPass() );
210+
rule->mSymbolNormZLevels.clear();
211+
}
212+
}
213+
214+
// create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
215+
// and prepare rendering queue
216+
QMap<int, int> zLevelsToNormLevels;
217+
int maxNormLevel = -1;
218+
mRenderQueue.levels.clear();
219+
foreach( int zLevel, symbolZLevelsSet.toList() )
220+
{
221+
zLevelsToNormLevels[zLevel] = ++maxNormLevel;
222+
mRenderQueue.levels.append( RenderLevel( zLevel ) );
223+
QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
224+
}
225+
226+
// prepare list of normalized levels for each rule
227+
for ( it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
228+
{
229+
Rule* rule = *it;
230+
QgsSymbolV2* s = rule->symbol();
231+
for ( int i = 0; i < s->symbolLayerCount(); i++ )
232+
{
233+
int normLevel = zLevelsToNormLevels.value( s->symbolLayer( i )->renderingPass() );
234+
rule->mSymbolNormZLevels.append( normLevel );
235+
}
186236
}
187237
}
188238

189239
void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
190240
{
241+
//
242+
// do the actual rendering
243+
//
244+
245+
// TODO: selected, markers
246+
bool selected = false;
247+
bool drawVertexMarker = false;
248+
249+
// go through all levels
250+
foreach( const RenderLevel& level, mRenderQueue.levels )
251+
{
252+
//QgsDebugMsg(QString("level %1").arg(level.zIndex));
253+
// go through all jobs at the level
254+
foreach( const RenderJob* job, level.jobs )
255+
{
256+
//QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
257+
// render feature - but only with symbol layers with specified zIndex
258+
QgsSymbolV2* s = job->symbol;
259+
int count = s->symbolLayerCount();
260+
for ( int i = 0; i < count; i++ )
261+
{
262+
// TODO: better solution for this
263+
// renderFeatureWithSymbol asks which symbol layer to draw
264+
// but there are multiple transforms going on!
265+
if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
266+
{
267+
renderFeatureWithSymbol( *job->f, job->symbol, context, i, selected, drawVertexMarker );
268+
}
269+
}
270+
}
271+
}
272+
273+
// TODO:
274+
// clear render queue, render jobs
275+
276+
foreach( QgsFeature* f, mCurrentFeatures )
277+
{
278+
delete f;
279+
}
280+
mCurrentFeatures.clear();
281+
191282
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
192283
{
193284
Rule* rule = *it;

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,32 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
8181

8282
// temporary
8383
QgsExpression* mFilter;
84+
public: // TODO
85+
QList<int> mSymbolNormZLevels; // normalized
86+
};
87+
88+
// TODO: use QVarLengthArray instead of QList
89+
90+
// rendering job: a feature to be rendered with a particular symbol
91+
struct RenderJob
92+
{
93+
RenderJob( QgsFeature* _f, QgsSymbolV2* _s ) : f( _f ), symbol( _s ) {}
94+
QgsFeature* f;
95+
QgsSymbolV2* symbol;
96+
};
97+
98+
// render level: a list of jobs to be drawn at particular level
99+
struct RenderLevel
100+
{
101+
RenderLevel( int z ): zIndex( z ) {}
102+
int zIndex;
103+
QList<RenderJob*> jobs;
104+
};
105+
106+
// rendering queue: a list of rendering levels and jobs
107+
struct RenderQueue
108+
{
109+
QList<RenderLevel> levels;
84110
};
85111

86112
/////
@@ -154,6 +180,9 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
154180
QList<Rule*> mCurrentRules;
155181
QgsSymbolV2* mCurrentSymbol;
156182

183+
RenderQueue mRenderQueue;
184+
QList<QgsFeature*> mCurrentFeatures;
185+
//QList<RenderJob*> mCurrentRenderJobs;
157186
};
158187

159188
#endif // QGSRULEBASEDRENDERERV2_H

0 commit comments

Comments
 (0)
Please sign in to comment.