Skip to content

Commit

Permalink
GRASS topology layers - display internal topo info
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Sep 13, 2013
1 parent fd4515e commit 3ecaa5f
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 79 deletions.
46 changes: 28 additions & 18 deletions src/plugins/grass/qgsgrassplugin.cpp
Expand Up @@ -321,11 +321,14 @@ void QgsGrassPlugin::addVector()
QString field;
QString type;

QRegExp rx( "(\\d+)_(.+)" );
if ( rx.indexIn( sel->layer ) != -1 )
if ( !sel->layer.startsWith( "topo_" ) )
{
field = rx.cap( 1 );
type = rx.cap( 2 );
QRegExp rx( "(\\d+)_(.+)" );
if ( rx.indexIn( sel->layer ) != -1 )
{
field = rx.cap( 1 );
type = rx.cap( 2 );
}
}

// Set location
Expand Down Expand Up @@ -355,26 +358,33 @@ void QgsGrassPlugin::addVector()

if ( level >= 2 )
{
// Count layers
int cnt = 0;
int ncidx = Vect_cidx_get_num_fields( &map );

for ( int i = 0; i < ncidx; i++ )
if ( !sel->layer.startsWith( "topo_" ) )
{
int field = Vect_cidx_get_field_number( &map, i );
// Count layers
int cnt = 0;
int ncidx = Vect_cidx_get_num_fields( &map );

if ( Vect_cidx_get_type_count( &map, field, GV_POINT | GV_LINE | GV_AREA ) > 0 ||
( field > 1 && Vect_cidx_get_type_count( &map, field, GV_BOUNDARY ) ) )
for ( int i = 0; i < ncidx; i++ )
{
cnt++;
int field = Vect_cidx_get_field_number( &map, i );

if ( Vect_cidx_get_type_count( &map, field, GV_POINT | GV_LINE | GV_AREA ) > 0 ||
( field > 1 && Vect_cidx_get_type_count( &map, field, GV_BOUNDARY ) ) )
{
cnt++;
}
}
}

if ( cnt > 1 )
{
name.append( " " + field );
if ( cnt > 1 )
{
name.append( " " + field );

// No need to ad type, the type is obvious from the legend
// No need to ad type, the type is obvious from the legend
}
}
else
{
name.append( " " + sel->layer );
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/providers/grass/qgsgrass.cpp
Expand Up @@ -877,6 +877,21 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( QString gisdbase,
list.append( l );
}
}

// add topology layers
if ( Vect_get_num_primitives( &map, GV_POINTS ) > 0 )
{
list.append( "topo_point" );
}
if ( Vect_get_num_primitives( &map, GV_LINES ) > 0 )
{
list.append( "topo_line" );
}
if ( Vect_get_num_nodes( &map ) > 0 )
{
list.append( "topo_node" );
}

Vect_close( &map );

return list;
Expand Down
138 changes: 115 additions & 23 deletions src/providers/grass/qgsgrassfeatureiterator.cpp
Expand Up @@ -71,23 +71,28 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u
//apply selection rectangle
resetSelection( 0 );

BOUND_BOX box;
box.N = rect.yMaximum(); box.S = rect.yMinimum();
box.E = rect.xMaximum(); box.W = rect.xMinimum();
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;

if ( !useIntersect )
{ // select by bounding boxes only
BOUND_BOX box;
box.N = rect.yMaximum(); box.S = rect.yMinimum();
box.E = rect.xMaximum(); box.W = rect.xMinimum();
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;
if ( P->mLayerType == QgsGrassProvider::POINT || P->mLayerType == QgsGrassProvider::CENTROID ||
P->mLayerType == QgsGrassProvider::LINE || P->mLayerType == QgsGrassProvider::FACE ||
P->mLayerType == QgsGrassProvider::BOUNDARY )
P->mLayerType == QgsGrassProvider::BOUNDARY ||
P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
Vect_select_lines_by_box( P->mMap, &box, P->mGrassType, mList );
}
else if ( P->mLayerType == QgsGrassProvider::POLYGON )
{
Vect_select_areas_by_box( P->mMap, &box, mList );
}

else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
Vect_select_nodes_by_box( P->mMap, &box, mList );
}
}
else
{ // check intersection
Expand All @@ -106,14 +111,20 @@ void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool u

if ( P->mLayerType == QgsGrassProvider::POINT || P->mLayerType == QgsGrassProvider::CENTROID ||
P->mLayerType == QgsGrassProvider::LINE || P->mLayerType == QgsGrassProvider::FACE ||
P->mLayerType == QgsGrassProvider::BOUNDARY )
P->mLayerType == QgsGrassProvider::BOUNDARY ||
P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
Vect_select_lines_by_polygon( P->mMap, Polygon, 0, NULL, P->mGrassType, mList );
}
else if ( P->mLayerType == QgsGrassProvider::POLYGON )
{
Vect_select_areas_by_polygon( P->mMap, Polygon, 0, NULL, mList );
}
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
// There is no Vect_select_nodes_by_polygon but for nodes it is the same as by box
Vect_select_nodes_by_box( P->mMap, &box, mList );
}

Vect_destroy_line_struct( Polygon );
}
Expand Down Expand Up @@ -153,7 +164,8 @@ bool QgsGrassFeatureIterator::nextFeature( QgsFeature& feature )
return false;
}

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

// Get next line/area id
int found = 0;
while ( mNextCidx < P->mCidxFieldNumCats )
while ( true )
{
Vect_cidx_get_cat_by_index( P->mMap, P->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
// Warning: selection array is only of type line/area of current layer -> check type first
if ( !( type & P->mGrassType ) )
continue;
QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 );
if ( P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
if ( mNextTopoId > Vect_get_num_lines( P->mMap ) ) break;
id = mNextTopoId;
type = Vect_read_line( P->mMap, 0, 0, mNextTopoId++ );
if ( !( type & P->mGrassType ) ) continue;
featureId = id;
}
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
if ( mNextTopoId > Vect_get_num_nodes( P->mMap ) ) break;
id = mNextTopoId;
type = 0;
mNextTopoId++;
featureId = id;
}
else
{
if ( mNextCidx >= P->mCidxFieldNumCats ) break;

// The 'id' is a unique id of a GRASS geometry object (point, line, area)
// but it cannot be used as QgsFeatureId because one geometry object may
// represent more features because it may have more categories.
featureId = makeFeatureId( id, cat );
Vect_cidx_get_cat_by_index( P->mMap, P->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
// Warning: selection array is only of type line/area of current layer -> check type first
if ( !( type & P->mGrassType ) )
continue;

// The 'id' is a unique id of a GRASS geometry object (point, line, area)
// but it cannot be used as QgsFeatureId because one geometry object may
// represent more features because it may have more categories.
featureId = makeFeatureId( id, cat );
}

if ( filterById && featureId != mRequest.filterFid() )
continue;
Expand Down Expand Up @@ -202,10 +236,52 @@ bool QgsGrassFeatureIterator::nextFeature( QgsFeature& feature )
else
setFeatureGeometry( feature, id, type );

if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
P->setFeatureAttributes( P->mLayerId, cat, &feature, mRequest.subsetOfAttributes() );
if ( ! P->isTopoType() )
{
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
P->setFeatureAttributes( P->mLayerId, cat, &feature, mRequest.subsetOfAttributes() );
else
P->setFeatureAttributes( P->mLayerId, cat, &feature );
}
else
P->setFeatureAttributes( P->mLayerId, cat, &feature );
{
feature.setAttribute( 0, id );
if ( P->mLayerType == QgsGrassProvider::TOPO_POINT || P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
feature.setAttribute( 1, P->primitiveTypeName( type ) );

int node1, node2;
Vect_get_line_nodes( P->mMap, id, &node1, &node2 );
feature.setAttribute( 2, node1 );
if ( P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
feature.setAttribute( 3, node2 );
}
}

if ( P->mLayerType == QgsGrassProvider::TOPO_LINE )
{
if ( type == GV_BOUNDARY )
{
int left, right;
Vect_get_line_areas( P->mMap, id, &left, &right );
feature.setAttribute( 4, left );
feature.setAttribute( 5, right );
}
}
else if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
QString lines;
int nlines = Vect_get_node_n_lines( P->mMap, id );
for ( int i = 0; i < nlines; i++ )
{
int line = Vect_get_node_line( P->mMap, id, i );
if ( i > 0 ) lines += ",";
lines += QString::number( line );
}
feature.setAttribute( 1, lines );
}
}

feature.setValid( true );

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

mNextCidx = 0;
mNextTopoId = 1;

return true;
}
Expand Down Expand Up @@ -258,6 +335,7 @@ void QgsGrassFeatureIterator::resetSelection( bool sel )
QgsDebugMsg( "entered." );
memset( mSelection, ( int ) sel, mSelectionSize );
mNextCidx = 0;
mNextTopoId = 1;
}


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

// TODO int may be 64 bits (memcpy)
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || P->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */
{
Vect_read_line( P->mMap, mPoints, mCats, id );
if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
double x, y, z;
Vect_get_node_coor( P->mMap, id, &x, &y, &z );
Vect_reset_line( mPoints );
Vect_append_point( mPoints, x, y, z );
}
else
{
Vect_read_line( P->mMap, mPoints, 0, id );
}
int npoints = mPoints->n_points;

if ( type & GV_POINTS )
if ( P->mLayerType == QgsGrassProvider::TOPO_NODE )
{
wkbsize = 1 + 4 + 2 * 8;
}
else if ( type & GV_POINTS )
{
wkbsize = 1 + 4 + 2 * 8;
}
Expand Down
2 changes: 2 additions & 0 deletions src/providers/grass/qgsgrassfeatureiterator.h
Expand Up @@ -60,7 +60,9 @@ class QgsGrassFeatureIterator : public QgsAbstractFeatureIterator
char *mSelection; // !UPDATE!
int mSelectionSize; // !UPDATE! Size of selection array

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

/*! reset selection */
void resetSelection( bool sel );
Expand Down

0 comments on commit 3ecaa5f

Please sign in to comment.