14
14
***************************************************************************/
15
15
16
16
#include < QObject>
17
+ #include < QTextCodec>
17
18
18
19
#include " qgsgrassfeatureiterator.h"
19
20
#include " qgsgrassprovider.h"
@@ -27,30 +28,17 @@ extern "C"
27
28
#include < grass/Vect.h>
28
29
}
29
30
30
- // from provider:
31
- // - mMap, mMaps, mMapVersion
32
- // - mLayers, mLayerId
33
- // - mCidxFieldNumCats, mCidxFieldIndex
34
- // - mGrassType, mQgisType
35
- // - mapOutdated(), updateMap(), update()
36
- // - attributesOutdated(), loadAttributes()
37
- // - setFeatureAttributes()
38
-
39
- QgsGrassFeatureIterator::QgsGrassFeatureIterator ( QgsGrassProvider* p, const QgsFeatureRequest& request )
40
- : QgsAbstractFeatureIterator( request ), P( p )
41
- {
42
- P->mActiveIterators << this ;
43
-
44
- // check if outdated and update if necessary
45
- P->ensureUpdated ();
46
31
32
+ QgsGrassFeatureIterator::QgsGrassFeatureIterator ( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
33
+ : QgsAbstractFeatureIteratorFromSource( source, ownSource, request )
34
+ {
47
35
// Init structures
48
36
mPoints = Vect_new_line_struct ();
49
37
mCats = Vect_new_cats_struct ();
50
38
mList = Vect_new_list ();
51
39
52
40
// Create selection array
53
- allocateSelection ( P ->mMap );
41
+ allocateSelection ( mSource ->mMap );
54
42
resetSelection ( 1 );
55
43
56
44
if ( request.filterType () == QgsFeatureRequest::FilterRect )
@@ -78,20 +66,20 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u
78
66
79
67
if ( !useIntersect )
80
68
{ // select by bounding boxes only
81
- if ( P ->mLayerType == QgsGrassProvider::POINT || P ->mLayerType == QgsGrassProvider::CENTROID ||
82
- P ->mLayerType == QgsGrassProvider::LINE || P ->mLayerType == QgsGrassProvider::FACE ||
83
- P ->mLayerType == QgsGrassProvider::BOUNDARY ||
84
- P ->mLayerType == QgsGrassProvider::TOPO_POINT || P ->mLayerType == QgsGrassProvider::TOPO_LINE )
69
+ if ( mSource ->mLayerType == QgsGrassProvider::POINT || mSource ->mLayerType == QgsGrassProvider::CENTROID ||
70
+ mSource ->mLayerType == QgsGrassProvider::LINE || mSource ->mLayerType == QgsGrassProvider::FACE ||
71
+ mSource ->mLayerType == QgsGrassProvider::BOUNDARY ||
72
+ mSource ->mLayerType == QgsGrassProvider::TOPO_POINT || mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
85
73
{
86
- Vect_select_lines_by_box ( P ->mMap , &box, P ->mGrassType , mList );
74
+ Vect_select_lines_by_box ( mSource ->mMap , &box, mSource ->mGrassType , mList );
87
75
}
88
- else if ( P ->mLayerType == QgsGrassProvider::POLYGON )
76
+ else if ( mSource ->mLayerType == QgsGrassProvider::POLYGON )
89
77
{
90
- Vect_select_areas_by_box ( P ->mMap , &box, mList );
78
+ Vect_select_areas_by_box ( mSource ->mMap , &box, mList );
91
79
}
92
- else if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
80
+ else if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
93
81
{
94
- Vect_select_nodes_by_box ( P ->mMap , &box, mList );
82
+ Vect_select_nodes_by_box ( mSource ->mMap , &box, mList );
95
83
}
96
84
}
97
85
else
@@ -109,21 +97,21 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u
109
97
Vect_append_point ( Polygon, rect.xMinimum (), rect.yMaximum (), 0 );
110
98
Vect_append_point ( Polygon, rect.xMinimum (), rect.yMinimum (), 0 );
111
99
112
- if ( P ->mLayerType == QgsGrassProvider::POINT || P ->mLayerType == QgsGrassProvider::CENTROID ||
113
- P ->mLayerType == QgsGrassProvider::LINE || P ->mLayerType == QgsGrassProvider::FACE ||
114
- P ->mLayerType == QgsGrassProvider::BOUNDARY ||
115
- P ->mLayerType == QgsGrassProvider::TOPO_POINT || P ->mLayerType == QgsGrassProvider::TOPO_LINE )
100
+ if ( mSource ->mLayerType == QgsGrassProvider::POINT || mSource ->mLayerType == QgsGrassProvider::CENTROID ||
101
+ mSource ->mLayerType == QgsGrassProvider::LINE || mSource ->mLayerType == QgsGrassProvider::FACE ||
102
+ mSource ->mLayerType == QgsGrassProvider::BOUNDARY ||
103
+ mSource ->mLayerType == QgsGrassProvider::TOPO_POINT || mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
116
104
{
117
- Vect_select_lines_by_polygon ( P ->mMap , Polygon, 0 , NULL , P ->mGrassType , mList );
105
+ Vect_select_lines_by_polygon ( mSource ->mMap , Polygon, 0 , NULL , mSource ->mGrassType , mList );
118
106
}
119
- else if ( P ->mLayerType == QgsGrassProvider::POLYGON )
107
+ else if ( mSource ->mLayerType == QgsGrassProvider::POLYGON )
120
108
{
121
- Vect_select_areas_by_polygon ( P ->mMap , Polygon, 0 , NULL , mList );
109
+ Vect_select_areas_by_polygon ( mSource ->mMap , Polygon, 0 , NULL , mList );
122
110
}
123
- else if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
111
+ else if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
124
112
{
125
113
// There is no Vect_select_nodes_by_polygon but for nodes it is the same as by box
126
- Vect_select_nodes_by_box ( P ->mMap , &box, mList );
114
+ Vect_select_nodes_by_box ( mSource ->mMap , &box, mList );
127
115
}
128
116
129
117
Vect_destroy_line_struct ( Polygon );
@@ -158,14 +146,16 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
158
146
159
147
QgsDebugMsgLevel ( " entered." , 3 );
160
148
149
+ /* TODO: handle editing
161
150
if ( P->isEdited() || P->isFrozen() || !P->mValid )
162
151
{
163
152
close();
164
153
return false;
165
154
}
155
+ */
166
156
167
157
// TODO: is this necessary? the same is checked below
168
- if ( !P-> isTopoType () && ( P ->mCidxFieldIndex < 0 || mNextCidx >= P ->mCidxFieldNumCats ) )
158
+ if ( !QgsGrassProvider:: isTopoType ( mSource -> mLayerType ) && ( mSource ->mCidxFieldIndex < 0 || mNextCidx >= mSource ->mCidxFieldNumCats ) )
169
159
{
170
160
close ();
171
161
return false ; // No features, no features in this layer
@@ -178,29 +168,29 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
178
168
while ( true )
179
169
{
180
170
QgsDebugMsgLevel ( QString ( " mNextTopoId = %1" ).arg ( mNextTopoId ), 3 );
181
- if ( P ->mLayerType == QgsGrassProvider::TOPO_POINT || P ->mLayerType == QgsGrassProvider::TOPO_LINE )
171
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_POINT || mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
182
172
{
183
- if ( mNextTopoId > Vect_get_num_lines ( P ->mMap ) ) break ;
173
+ if ( mNextTopoId > Vect_get_num_lines ( mSource ->mMap ) ) break ;
184
174
id = mNextTopoId ;
185
- type = Vect_read_line ( P ->mMap , 0 , 0 , mNextTopoId ++ );
186
- if ( !( type & P ->mGrassType ) ) continue ;
175
+ type = Vect_read_line ( mSource ->mMap , 0 , 0 , mNextTopoId ++ );
176
+ if ( !( type & mSource ->mGrassType ) ) continue ;
187
177
featureId = id;
188
178
}
189
- else if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
179
+ else if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
190
180
{
191
- if ( mNextTopoId > Vect_get_num_nodes ( P ->mMap ) ) break ;
181
+ if ( mNextTopoId > Vect_get_num_nodes ( mSource ->mMap ) ) break ;
192
182
id = mNextTopoId ;
193
183
type = 0 ;
194
184
mNextTopoId ++;
195
185
featureId = id;
196
186
}
197
187
else
198
188
{
199
- if ( mNextCidx >= P ->mCidxFieldNumCats ) break ;
189
+ if ( mNextCidx >= mSource ->mCidxFieldNumCats ) break ;
200
190
201
- Vect_cidx_get_cat_by_index ( P ->mMap , P ->mCidxFieldIndex , mNextCidx ++, &cat, &type, &id );
191
+ Vect_cidx_get_cat_by_index ( mSource ->mMap , mSource ->mCidxFieldIndex , mNextCidx ++, &cat, &type, &id );
202
192
// Warning: selection array is only of type line/area of current layer -> check type first
203
- if ( !( type & P ->mGrassType ) )
193
+ if ( !( type & mSource ->mGrassType ) )
204
194
continue ;
205
195
206
196
// The 'id' is a unique id of a GRASS geometry object (point, line, area)
@@ -228,54 +218,54 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
228
218
QgsDebugMsgLevel ( QString ( " cat = %1 type = %2 id = %3 fatureId = %4" ).arg ( cat ).arg ( type ).arg ( id ).arg ( featureId ), 3 );
229
219
230
220
feature.setFeatureId ( featureId );
231
- feature.initAttributes ( P-> fields () .count () );
232
- feature.setFields ( &P-> fields () ); // allow name-based attribute lookups
221
+ feature.initAttributes ( mSource -> mFields .count () );
222
+ feature.setFields ( &mSource -> mFields ); // allow name-based attribute lookups
233
223
234
224
if ( mRequest .flags () & QgsFeatureRequest::NoGeometry )
235
225
feature.setGeometry ( 0 );
236
226
else
237
227
setFeatureGeometry ( feature, id, type );
238
228
239
- if ( ! P-> isTopoType () )
229
+ if ( ! QgsGrassProvider:: isTopoType ( mSource -> mLayerType ) )
240
230
{
241
231
if ( mRequest .flags () & QgsFeatureRequest::SubsetOfAttributes )
242
- P-> setFeatureAttributes ( P-> mLayerId , cat, &feature, mRequest .subsetOfAttributes () );
232
+ setFeatureAttributes ( cat, &feature, mRequest .subsetOfAttributes () );
243
233
else
244
- P-> setFeatureAttributes ( P-> mLayerId , cat, &feature );
234
+ setFeatureAttributes ( cat, &feature );
245
235
}
246
236
else
247
237
{
248
238
feature.setAttribute ( 0 , id );
249
- if ( P ->mLayerType == QgsGrassProvider::TOPO_POINT || P ->mLayerType == QgsGrassProvider::TOPO_LINE )
239
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_POINT || mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
250
240
{
251
- feature.setAttribute ( 1 , P-> primitiveTypeName ( type ) );
241
+ feature.setAttribute ( 1 , QgsGrassProvider:: primitiveTypeName ( type ) );
252
242
253
243
int node1, node2;
254
- Vect_get_line_nodes ( P ->mMap , id, &node1, &node2 );
244
+ Vect_get_line_nodes ( mSource ->mMap , id, &node1, &node2 );
255
245
feature.setAttribute ( 2 , node1 );
256
- if ( P ->mLayerType == QgsGrassProvider::TOPO_LINE )
246
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
257
247
{
258
248
feature.setAttribute ( 3 , node2 );
259
249
}
260
250
}
261
251
262
- if ( P ->mLayerType == QgsGrassProvider::TOPO_LINE )
252
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_LINE )
263
253
{
264
254
if ( type == GV_BOUNDARY )
265
255
{
266
256
int left, right;
267
- Vect_get_line_areas ( P ->mMap , id, &left, &right );
257
+ Vect_get_line_areas ( mSource ->mMap , id, &left, &right );
268
258
feature.setAttribute ( 4 , left );
269
259
feature.setAttribute ( 5 , right );
270
260
}
271
261
}
272
- else if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
262
+ else if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
273
263
{
274
264
QString lines;
275
- int nlines = Vect_get_node_n_lines ( P ->mMap , id );
265
+ int nlines = Vect_get_node_n_lines ( mSource ->mMap , id );
276
266
for ( int i = 0 ; i < nlines; i++ )
277
267
{
278
- int line = Vect_get_node_line ( P ->mMap , id, i );
268
+ int line = Vect_get_node_line ( mSource ->mMap , id, i );
279
269
if ( i > 0 ) lines += " ," ;
280
270
lines += QString::number ( line );
281
271
}
@@ -296,11 +286,10 @@ bool QgsGrassFeatureIterator::rewind()
296
286
if ( mClosed )
297
287
return false ;
298
288
289
+ /* TODO: handle editing
299
290
if ( P->isEdited() || P->isFrozen() || !P->mValid )
300
291
return false;
301
-
302
- // not sure if this really should be here
303
- P->ensureUpdated ();
292
+ */
304
293
305
294
mNextCidx = 0 ;
306
295
mNextTopoId = 1 ;
@@ -313,7 +302,7 @@ bool QgsGrassFeatureIterator::close()
313
302
if ( mClosed )
314
303
return false ;
315
304
316
- P-> mActiveIterators . remove ( this );
305
+ iteratorClosed ( );
317
306
318
307
// finalization
319
308
Vect_destroy_line_struct ( mPoints );
@@ -369,22 +358,22 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
369
358
int wkbsize;
370
359
371
360
// TODO int may be 64 bits (memcpy)
372
- if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || P ->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */
361
+ if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || mSource ->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */
373
362
{
374
- if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
363
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
375
364
{
376
365
double x, y, z;
377
- Vect_get_node_coor ( P ->mMap , id, &x, &y, &z );
366
+ Vect_get_node_coor ( mSource ->mMap , id, &x, &y, &z );
378
367
Vect_reset_line ( mPoints );
379
368
Vect_append_point ( mPoints , x, y, z );
380
369
}
381
370
else
382
371
{
383
- Vect_read_line ( P ->mMap , mPoints , 0 , id );
372
+ Vect_read_line ( mSource ->mMap , mPoints , 0 , id );
384
373
}
385
374
int npoints = mPoints ->n_points ;
386
375
387
- if ( P ->mLayerType == QgsGrassProvider::TOPO_NODE )
376
+ if ( mSource ->mLayerType == QgsGrassProvider::TOPO_NODE )
388
377
{
389
378
wkbsize = 1 + 4 + 2 * 8 ;
390
379
}
@@ -406,7 +395,7 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
406
395
wkbp += 1 ;
407
396
408
397
/* WKB type */
409
- memcpy ( wkbp, &P ->mQgisType , 4 );
398
+ memcpy ( wkbp, &mSource ->mQgisType , 4 );
410
399
wkbp += 4 ;
411
400
412
401
/* Number of rings */
@@ -434,7 +423,7 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
434
423
}
435
424
else // GV_AREA
436
425
{
437
- Vect_get_area_points ( P ->mMap , id, mPoints );
426
+ Vect_get_area_points ( mSource ->mMap , id, mPoints );
438
427
int npoints = mPoints ->n_points ;
439
428
440
429
wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8 ; // size without islands
@@ -443,11 +432,11 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
443
432
int offset = 1 ;
444
433
445
434
/* WKB type */
446
- memcpy ( wkb + offset, &P ->mQgisType , 4 );
435
+ memcpy ( wkb + offset, &mSource ->mQgisType , 4 );
447
436
offset += 4 ;
448
437
449
438
/* Number of rings */
450
- int nisles = Vect_get_area_num_isles ( P ->mMap , id );
439
+ int nisles = Vect_get_area_num_isles ( mSource ->mMap , id );
451
440
int nrings = 1 + nisles;
452
441
memcpy ( wkb + offset, &nrings, 4 );
453
442
offset += 4 ;
@@ -465,7 +454,7 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
465
454
/* Isles */
466
455
for ( int i = 0 ; i < nisles; i++ )
467
456
{
468
- Vect_get_isle_points ( P ->mMap , Vect_get_area_isle ( P ->mMap , id, i ), mPoints );
457
+ Vect_get_isle_points ( mSource ->mMap , Vect_get_area_isle ( mSource ->mMap , id, i ), mPoints );
469
458
npoints = mPoints ->n_points ;
470
459
471
460
// add space
@@ -492,3 +481,111 @@ QgsFeatureId QgsGrassFeatureIterator::makeFeatureId( int grassId, int cat )
492
481
// we can create unique QgsFeatureId from GRASS id and cat
493
482
return ( QgsFeatureId )grassId * 1000000000 + cat;
494
483
}
484
+
485
+
486
+
487
+ /* * Set feature attributes */
488
+ void QgsGrassFeatureIterator::setFeatureAttributes ( int cat, QgsFeature *feature )
489
+ {
490
+ #if QGISDEBUG > 3
491
+ QgsDebugMsg ( QString ( " setFeatureAttributes cat = %1" ).arg ( cat ) );
492
+ #endif
493
+ GLAYER& glayer = QgsGrassProvider::mLayers [mSource ->mLayerId ];
494
+
495
+ if ( glayer.nColumns > 0 )
496
+ {
497
+ // find cat
498
+ GATT key;
499
+ key.cat = cat;
500
+
501
+ GATT *att = ( GATT * ) bsearch ( &key, glayer.attributes , glayer.nAttributes ,
502
+ sizeof ( GATT ), QgsGrassProvider::cmpAtt );
503
+
504
+ feature->initAttributes ( glayer.nColumns );
505
+
506
+ for ( int i = 0 ; i < glayer.nColumns ; i++ )
507
+ {
508
+ if ( att != NULL )
509
+ {
510
+ QByteArray cstr ( att->values [i] );
511
+ feature->setAttribute ( i, QgsGrassProvider::convertValue ( glayer.fields [i].type (), mSource ->mEncoding ->toUnicode ( cstr ) ) );
512
+ }
513
+ else /* it may happen that attributes are missing -> set to empty string */
514
+ {
515
+ feature->setAttribute ( i, QVariant () );
516
+ }
517
+ }
518
+ }
519
+ else
520
+ {
521
+ feature->initAttributes ( 1 );
522
+ feature->setAttribute ( 0 , QVariant ( cat ) );
523
+ }
524
+ }
525
+
526
+ void QgsGrassFeatureIterator::setFeatureAttributes ( int cat, QgsFeature *feature, const QgsAttributeList& attlist )
527
+ {
528
+ #if QGISDEBUG > 3
529
+ QgsDebugMsg ( QString ( " setFeatureAttributes cat = %1" ).arg ( cat ) );
530
+ #endif
531
+ GLAYER& glayer = QgsGrassProvider::mLayers [mSource ->mLayerId ];
532
+
533
+ if ( glayer.nColumns > 0 )
534
+ {
535
+ // find cat
536
+ GATT key;
537
+ key.cat = cat;
538
+ GATT *att = ( GATT * ) bsearch ( &key, glayer.attributes , glayer.nAttributes ,
539
+ sizeof ( GATT ), QgsGrassProvider::cmpAtt );
540
+
541
+ feature->initAttributes ( glayer.nColumns );
542
+
543
+ for ( QgsAttributeList::const_iterator iter = attlist.begin (); iter != attlist.end (); ++iter )
544
+ {
545
+ if ( att != NULL )
546
+ {
547
+ QByteArray cstr ( att->values [*iter] );
548
+ feature->setAttribute ( *iter, QgsGrassProvider::convertValue ( glayer.fields [*iter].type (), mSource ->mEncoding ->toUnicode ( cstr ) ) );
549
+ }
550
+ else /* it may happen that attributes are missing -> set to empty string */
551
+ {
552
+ feature->setAttribute ( *iter, QVariant () );
553
+ }
554
+ }
555
+ }
556
+ else
557
+ {
558
+ feature->initAttributes ( 1 );
559
+ feature->setAttribute ( 0 , QVariant ( cat ) );
560
+ }
561
+ }
562
+
563
+
564
+ // ------------------
565
+
566
+
567
+ QgsGrassFeatureSource::QgsGrassFeatureSource ( const QgsGrassProvider* p )
568
+ : mMap( p->mMap )
569
+ , mLayerType( p->mLayerType )
570
+ , mGrassType( p->mGrassType )
571
+ , mLayerId( p->mLayerId )
572
+ , mQgisType( p->mQgisType )
573
+ , mCidxFieldIndex( p->mCidxFieldIndex )
574
+ , mCidxFieldNumCats( p->mCidxFieldNumCats )
575
+ , mFields( p->fields () )
576
+ , mEncoding( p->mEncoding )
577
+ {
578
+ int layerId = QgsGrassProvider::openLayer ( p->mGisdbase , p->mLocation , p->mMapset , p->mMapName , p->mLayerField );
579
+
580
+ Q_ASSERT ( layerId == mLayerId );
581
+ }
582
+
583
+ QgsGrassFeatureSource::~QgsGrassFeatureSource ()
584
+ {
585
+ QgsGrassProvider::closeLayer ( mLayerId );
586
+ }
587
+
588
+ QgsFeatureIterator QgsGrassFeatureSource::getFeatures ( const QgsFeatureRequest& request )
589
+ {
590
+ return QgsFeatureIterator ( new QgsGrassFeatureIterator ( this , false , request ) );
591
+ }
0 commit comments