Skip to content

Commit 3ecaa5f

Browse files
committed
GRASS topology layers - display internal topo info
1 parent fd4515e commit 3ecaa5f

File tree

6 files changed

+285
-79
lines changed

6 files changed

+285
-79
lines changed

src/plugins/grass/qgsgrassplugin.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,14 @@ void QgsGrassPlugin::addVector()
321321
QString field;
322322
QString type;
323323

324-
QRegExp rx( "(\\d+)_(.+)" );
325-
if ( rx.indexIn( sel->layer ) != -1 )
324+
if ( !sel->layer.startsWith( "topo_" ) )
326325
{
327-
field = rx.cap( 1 );
328-
type = rx.cap( 2 );
326+
QRegExp rx( "(\\d+)_(.+)" );
327+
if ( rx.indexIn( sel->layer ) != -1 )
328+
{
329+
field = rx.cap( 1 );
330+
type = rx.cap( 2 );
331+
}
329332
}
330333

331334
// Set location
@@ -355,26 +358,33 @@ void QgsGrassPlugin::addVector()
355358

356359
if ( level >= 2 )
357360
{
358-
// Count layers
359-
int cnt = 0;
360-
int ncidx = Vect_cidx_get_num_fields( &map );
361-
362-
for ( int i = 0; i < ncidx; i++ )
361+
if ( !sel->layer.startsWith( "topo_" ) )
363362
{
364-
int field = Vect_cidx_get_field_number( &map, i );
363+
// Count layers
364+
int cnt = 0;
365+
int ncidx = Vect_cidx_get_num_fields( &map );
365366

366-
if ( Vect_cidx_get_type_count( &map, field, GV_POINT | GV_LINE | GV_AREA ) > 0 ||
367-
( field > 1 && Vect_cidx_get_type_count( &map, field, GV_BOUNDARY ) ) )
367+
for ( int i = 0; i < ncidx; i++ )
368368
{
369-
cnt++;
369+
int field = Vect_cidx_get_field_number( &map, i );
370+
371+
if ( Vect_cidx_get_type_count( &map, field, GV_POINT | GV_LINE | GV_AREA ) > 0 ||
372+
( field > 1 && Vect_cidx_get_type_count( &map, field, GV_BOUNDARY ) ) )
373+
{
374+
cnt++;
375+
}
370376
}
371-
}
372377

373-
if ( cnt > 1 )
374-
{
375-
name.append( " " + field );
378+
if ( cnt > 1 )
379+
{
380+
name.append( " " + field );
376381

377-
// No need to ad type, the type is obvious from the legend
382+
// No need to ad type, the type is obvious from the legend
383+
}
384+
}
385+
else
386+
{
387+
name.append( " " + sel->layer );
378388
}
379389
}
380390

src/providers/grass/qgsgrass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,21 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( QString gisdbase,
877877
list.append( l );
878878
}
879879
}
880+
881+
// add topology layers
882+
if ( Vect_get_num_primitives( &map, GV_POINTS ) > 0 )
883+
{
884+
list.append( "topo_point" );
885+
}
886+
if ( Vect_get_num_primitives( &map, GV_LINES ) > 0 )
887+
{
888+
list.append( "topo_line" );
889+
}
890+
if ( Vect_get_num_nodes( &map ) > 0 )
891+
{
892+
list.append( "topo_node" );
893+
}
894+
880895
Vect_close( &map );
881896

882897
return list;

src/providers/grass/qgsgrassfeatureiterator.cpp

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,28 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u
7171
//apply selection rectangle
7272
resetSelection( 0 );
7373

74+
BOUND_BOX box;
75+
box.N = rect.yMaximum(); box.S = rect.yMinimum();
76+
box.E = rect.xMaximum(); box.W = rect.xMinimum();
77+
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;
78+
7479
if ( !useIntersect )
7580
{ // select by bounding boxes only
76-
BOUND_BOX box;
77-
box.N = rect.yMaximum(); box.S = rect.yMinimum();
78-
box.E = rect.xMaximum(); box.W = rect.xMinimum();
79-
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;
8081
if ( P->mLayerType == QgsGrassProvider::POINT || P->mLayerType == QgsGrassProvider::CENTROID ||
8182
P->mLayerType == QgsGrassProvider::LINE || P->mLayerType == QgsGrassProvider::FACE ||
82-
P->mLayerType == QgsGrassProvider::BOUNDARY )
83+
P->mLayerType == QgsGrassProvider::BOUNDARY ||
84+
P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
8385
{
8486
Vect_select_lines_by_box( P->mMap, &box, P->mGrassType, mList );
8587
}
8688
else if ( P->mLayerType == QgsGrassProvider::POLYGON )
8789
{
8890
Vect_select_areas_by_box( P->mMap, &box, mList );
8991
}
90-
92+
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
93+
{
94+
Vect_select_nodes_by_box( P->mMap, &box, mList );
95+
}
9196
}
9297
else
9398
{ // check intersection
@@ -106,14 +111,20 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u
106111

107112
if ( P->mLayerType == QgsGrassProvider::POINT || P->mLayerType == QgsGrassProvider::CENTROID ||
108113
P->mLayerType == QgsGrassProvider::LINE || P->mLayerType == QgsGrassProvider::FACE ||
109-
P->mLayerType == QgsGrassProvider::BOUNDARY )
114+
P->mLayerType == QgsGrassProvider::BOUNDARY ||
115+
P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
110116
{
111117
Vect_select_lines_by_polygon( P->mMap, Polygon, 0, NULL, P->mGrassType, mList );
112118
}
113119
else if ( P->mLayerType == QgsGrassProvider::POLYGON )
114120
{
115121
Vect_select_areas_by_polygon( P->mMap, Polygon, 0, NULL, mList );
116122
}
123+
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
124+
{
125+
// 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 );
127+
}
117128

118129
Vect_destroy_line_struct( Polygon );
119130
}
@@ -153,7 +164,8 @@ bool QgsGrassFeatureIterator::nextFeature( QgsFeature& feature )
153164
return false;
154165
}
155166

156-
if ( P->mCidxFieldIndex < 0 || mNextCidx >= P->mCidxFieldNumCats )
167+
// TODO: is this necessary? the same is checked below
168+
if ( !P->isTopoType() && ( P->mCidxFieldIndex < 0 || mNextCidx >= P->mCidxFieldNumCats ) )
157169
{
158170
close();
159171
return false; // No features, no features in this layer
@@ -163,17 +175,39 @@ bool QgsGrassFeatureIterator::nextFeature( QgsFeature& feature )
163175

164176
// Get next line/area id
165177
int found = 0;
166-
while ( mNextCidx < P->mCidxFieldNumCats )
178+
while ( true )
167179
{
168-
Vect_cidx_get_cat_by_index( P->mMap, P->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
169-
// Warning: selection array is only of type line/area of current layer -> check type first
170-
if ( !( type & P->mGrassType ) )
171-
continue;
180+
QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 );
181+
if ( P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
182+
{
183+
if ( mNextTopoId > Vect_get_num_lines( P->mMap ) ) break;
184+
id = mNextTopoId;
185+
type = Vect_read_line( P->mMap, 0, 0, mNextTopoId++ );
186+
if ( !( type & P->mGrassType ) ) continue;
187+
featureId = id;
188+
}
189+
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
190+
{
191+
if ( mNextTopoId > Vect_get_num_nodes( P->mMap ) ) break;
192+
id = mNextTopoId;
193+
type = 0;
194+
mNextTopoId++;
195+
featureId = id;
196+
}
197+
else
198+
{
199+
if ( mNextCidx >= P->mCidxFieldNumCats ) break;
172200

173-
// The 'id' is a unique id of a GRASS geometry object (point, line, area)
174-
// but it cannot be used as QgsFeatureId because one geometry object may
175-
// represent more features because it may have more categories.
176-
featureId = makeFeatureId( id, cat );
201+
Vect_cidx_get_cat_by_index( P->mMap, P->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
202+
// Warning: selection array is only of type line/area of current layer -> check type first
203+
if ( !( type & P->mGrassType ) )
204+
continue;
205+
206+
// The 'id' is a unique id of a GRASS geometry object (point, line, area)
207+
// but it cannot be used as QgsFeatureId because one geometry object may
208+
// represent more features because it may have more categories.
209+
featureId = makeFeatureId( id, cat );
210+
}
177211

178212
if ( filterById && featureId != mRequest.filterFid() )
179213
continue;
@@ -202,10 +236,52 @@ bool QgsGrassFeatureIterator::nextFeature( QgsFeature& feature )
202236
else
203237
setFeatureGeometry( feature, id, type );
204238

205-
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
206-
P->setFeatureAttributes( P->mLayerId, cat, &feature, mRequest.subsetOfAttributes() );
239+
if ( ! P->isTopoType() )
240+
{
241+
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
242+
P->setFeatureAttributes( P->mLayerId, cat, &feature, mRequest.subsetOfAttributes() );
243+
else
244+
P->setFeatureAttributes( P->mLayerId, cat, &feature );
245+
}
207246
else
208-
P->setFeatureAttributes( P->mLayerId, cat, &feature );
247+
{
248+
feature.setAttribute( 0, id );
249+
if ( P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
250+
{
251+
feature.setAttribute( 1, P->primitiveTypeName( type ) );
252+
253+
int node1, node2;
254+
Vect_get_line_nodes( P->mMap, id, &node1, &node2 );
255+
feature.setAttribute( 2, node1 );
256+
if ( P->mLayerType == QgsGrassProvider::TOPO_LINE )
257+
{
258+
feature.setAttribute( 3, node2 );
259+
}
260+
}
261+
262+
if ( P->mLayerType == QgsGrassProvider::TOPO_LINE )
263+
{
264+
if ( type == GV_BOUNDARY )
265+
{
266+
int left, right;
267+
Vect_get_line_areas( P->mMap, id, &left, &right );
268+
feature.setAttribute( 4, left );
269+
feature.setAttribute( 5, right );
270+
}
271+
}
272+
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
273+
{
274+
QString lines;
275+
int nlines = Vect_get_node_n_lines( P->mMap, id );
276+
for ( int i = 0; i < nlines; i++ )
277+
{
278+
int line = Vect_get_node_line( P->mMap, id, i );
279+
if ( i > 0 ) lines += ",";
280+
lines += QString::number( line );
281+
}
282+
feature.setAttribute( 1, lines );
283+
}
284+
}
209285

210286
feature.setValid( true );
211287

@@ -227,6 +303,7 @@ bool QgsGrassFeatureIterator::rewind()
227303
P->ensureUpdated();
228304

229305
mNextCidx = 0;
306+
mNextTopoId = 1;
230307

231308
return true;
232309
}
@@ -258,6 +335,7 @@ void QgsGrassFeatureIterator::resetSelection( bool sel )
258335
QgsDebugMsg( "entered." );
259336
memset( mSelection, ( int ) sel, mSelectionSize );
260337
mNextCidx = 0;
338+
mNextTopoId = 1;
261339
}
262340

263341

@@ -291,12 +369,26 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
291369
int wkbsize;
292370

293371
// TODO int may be 64 bits (memcpy)
294-
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */
372+
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || P->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */
295373
{
296-
Vect_read_line( P->mMap, mPoints, mCats, id );
374+
if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
375+
{
376+
double x, y, z;
377+
Vect_get_node_coor( P->mMap, id, &x, &y, &z );
378+
Vect_reset_line( mPoints );
379+
Vect_append_point( mPoints, x, y, z );
380+
}
381+
else
382+
{
383+
Vect_read_line( P->mMap, mPoints, 0, id );
384+
}
297385
int npoints = mPoints->n_points;
298386

299-
if ( type & GV_POINTS )
387+
if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
388+
{
389+
wkbsize = 1 + 4 + 2 * 8;
390+
}
391+
else if ( type & GV_POINTS )
300392
{
301393
wkbsize = 1 + 4 + 2 * 8;
302394
}

src/providers/grass/qgsgrassfeatureiterator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ class QgsGrassFeatureIterator : public QgsAbstractFeatureIterator
6060
char *mSelection; // !UPDATE!
6161
int mSelectionSize; // !UPDATE! Size of selection array
6262

63+
// Either mNextCidx or mNextTopoId is used according to type
6364
int mNextCidx; // !UPDATE! Next index in cidxFieldIndex to be read, used to find nextFeature
65+
int mNextTopoId; // !UPDATE! Next topology id to be read, used to find nextFeature, starts from 1
6466

6567
/*! reset selection */
6668
void resetSelection( bool sel );

0 commit comments

Comments
 (0)