2424#include " qgseventtracing.h"
2525#include " qgsexpressioncontextutils.h"
2626#include " qgsfeature3dhandler_p.h"
27+ #include " qgsfields.h"
2728#include " qgsline3dsymbol.h"
2829#include " qgspoint3dsymbol.h"
2930#include " qgspolygon3dsymbol.h"
@@ -132,6 +133,107 @@ void QgsCategorizedChunkLoader::processFeature( const QgsFeature &feature ) cons
132133 handler->processFeature ( feature, mContext );
133134}
134135
136+ QString QgsCategorizedChunkLoader::filter () const
137+ {
138+ const QgsVectorLayer *layer = mFactory ->mLayer ;
139+ const QgsFields fields = layer->fields ();
140+ const int attributeNumber = fields.lookupField ( mFactory ->mAttributeName );
141+ const bool isExpression = ( attributeNumber == -1 );
142+
143+ bool hasDefault = false ;
144+ bool defaultActive = false ;
145+ bool allActive = true ;
146+ bool noneActive = true ;
147+
148+ // we need to build lists of both inactive and active values, as either list may be required
149+ // depending on whether the default category is active or not
150+ QString activeValues;
151+ QString inactiveValues;
152+
153+ for ( const Qgs3DRendererCategory &category : std::as_const ( mFactory ->mCategories ) )
154+ {
155+ if ( category.value () == " " || QgsVariantUtils::isNull ( category.value () ) )
156+ {
157+ hasDefault = true ;
158+ defaultActive = category.renderState ();
159+ }
160+
161+ noneActive = noneActive && !category.renderState ();
162+ allActive = allActive && category.renderState ();
163+
164+ const bool isList = category.value ().userType () == QMetaType::Type::QVariantList;
165+ QString value = QgsExpression::quotedValue ( category.value (), static_cast <QMetaType::Type>( category.value ().userType () ) );
166+
167+ if ( !category.renderState () )
168+ {
169+ if ( value != " " )
170+ {
171+ if ( isList )
172+ {
173+ const QVariantList list = category.value ().toList ();
174+ for ( const QVariant &variant : list )
175+ {
176+ if ( !inactiveValues.isEmpty () )
177+ inactiveValues.append ( ' ,' );
178+
179+ inactiveValues.append ( QgsExpression::quotedValue ( variant, isExpression ? static_cast <QMetaType::Type>( variant.userType () ) : fields.at ( attributeNumber ).type () ) );
180+ }
181+ }
182+ else
183+ {
184+ if ( !inactiveValues.isEmpty () )
185+ inactiveValues.append ( ' ,' );
186+
187+ inactiveValues.append ( value );
188+ }
189+ }
190+ }
191+ else
192+ {
193+ if ( value != " " )
194+ {
195+ if ( isList )
196+ {
197+ const QVariantList list = category.value ().toList ();
198+ for ( const QVariant &variant : list )
199+ {
200+ if ( !activeValues.isEmpty () )
201+ activeValues.append ( ' ,' );
202+
203+ activeValues.append ( QgsExpression::quotedValue ( variant, isExpression ? static_cast <QMetaType::Type>( variant.userType () ) : fields.at ( attributeNumber ).type () ) );
204+ }
205+ }
206+ else
207+ {
208+ if ( !activeValues.isEmpty () )
209+ activeValues.append ( ' ,' );
210+
211+ activeValues.append ( value );
212+ }
213+ }
214+ }
215+ }
216+
217+ QString attr = isExpression ? mFactory ->mAttributeName : u" \" %1\" " _s.arg ( mFactory ->mAttributeName );
218+
219+ if ( allActive && hasDefault )
220+ {
221+ return QString ();
222+ }
223+ else if ( noneActive )
224+ {
225+ return u" FALSE" _s;
226+ }
227+ else if ( defaultActive )
228+ {
229+ return u" (%1) NOT IN (%2) OR (%1) IS NULL" _s.arg ( attr, inactiveValues );
230+ }
231+ else
232+ {
233+ return u" (%1) IN (%2)" _s.arg ( attr, activeValues );
234+ }
235+ }
236+
135237void QgsCategorizedChunkLoader::start ()
136238{
137239 QgsChunkNode *node = chunk ();
@@ -153,6 +255,7 @@ void QgsCategorizedChunkLoader::start()
153255 request.setDestinationCrs ( mContext .crs (), mContext .transformContext () );
154256 request.setSubsetOfAttributes ( attributesNames, layer->fields () );
155257 request.setFilterRect ( rect );
258+ request.setFilterExpression ( filter () );
156259
157260 //
158261 // this will be run in a background thread
0 commit comments