[GRASS] add/delete feature

This commit is contained in:
Radim Blazek 2015-09-18 00:11:35 +02:00
parent e970f4afee
commit d82a018f4d
7 changed files with 482 additions and 217 deletions

View File

@ -34,18 +34,18 @@ QgsGrassEditRenderer::QgsGrassEditRenderer()
, mMarkerRenderer( 0 )
{
QHash<int, QColor> colors;
colors.insert( QgsGrassProvider::TopoUndefined, QColor( 125, 125, 125 ) );
colors.insert( QgsGrassProvider::TopoLine, QColor( Qt::black ) );
colors.insert( QgsGrassProvider::TopoBoundary0, QColor( Qt::red ) );
colors.insert( QgsGrassProvider::TopoBoundary1, QColor( 255, 125, 0 ) );
colors.insert( QgsGrassProvider::TopoBoundary2, QColor( Qt::green ) );
colors.insert( QgsGrassVectorMap::TopoUndefined, QColor( 125, 125, 125 ) );
colors.insert( QgsGrassVectorMap::TopoLine, QColor( Qt::black ) );
colors.insert( QgsGrassVectorMap::TopoBoundary0, QColor( Qt::red ) );
colors.insert( QgsGrassVectorMap::TopoBoundary1, QColor( 255, 125, 0 ) );
colors.insert( QgsGrassVectorMap::TopoBoundary2, QColor( Qt::green ) );
QHash<int, QString> labels;
labels.insert( QgsGrassProvider::TopoUndefined, "Unknown type" );
labels.insert( QgsGrassProvider::TopoLine, "Line" );
labels.insert( QgsGrassProvider::TopoBoundary0, "Boundary (isolated)" );
labels.insert( QgsGrassProvider::TopoBoundary1, "Boundary (area on one side)" );
labels.insert( QgsGrassProvider::TopoBoundary2, "Boundary (areas on both sides)" );
labels.insert( QgsGrassVectorMap::TopoUndefined, "Unknown type" );
labels.insert( QgsGrassVectorMap::TopoLine, "Line" );
labels.insert( QgsGrassVectorMap::TopoBoundary0, "Boundary (isolated)" );
labels.insert( QgsGrassVectorMap::TopoBoundary1, "Boundary (area on one side)" );
labels.insert( QgsGrassVectorMap::TopoBoundary2, "Boundary (areas on both sides)" );
QgsCategoryList categoryList;
@ -61,15 +61,15 @@ QgsGrassEditRenderer::QgsGrassEditRenderer()
colors.clear();
labels.clear();
colors.insert( QgsGrassProvider::TopoPoint, QColor( 0, 0, 0 ) );
colors.insert( QgsGrassProvider::TopoCentroidIn, QColor( 0, 255, 0 ) );
colors.insert( QgsGrassProvider::TopoCentroidOut, QColor( 255, 0, 0 ) );
colors.insert( QgsGrassProvider::TopoCentroidDupl, QColor( 255, 0, 255 ) );
colors.insert( QgsGrassVectorMap::TopoPoint, QColor( 0, 0, 0 ) );
colors.insert( QgsGrassVectorMap::TopoCentroidIn, QColor( 0, 255, 0 ) );
colors.insert( QgsGrassVectorMap::TopoCentroidOut, QColor( 255, 0, 0 ) );
colors.insert( QgsGrassVectorMap::TopoCentroidDupl, QColor( 255, 0, 255 ) );
labels.insert( QgsGrassProvider::TopoPoint, "Point" );
labels.insert( QgsGrassProvider::TopoCentroidIn, "Centroid in area" );
labels.insert( QgsGrassProvider::TopoCentroidOut, "Centroid outside area" );
labels.insert( QgsGrassProvider::TopoCentroidDupl, "Duplicate centroid" );
labels.insert( QgsGrassVectorMap::TopoPoint, "Point" );
labels.insert( QgsGrassVectorMap::TopoCentroidIn, "Centroid in area" );
labels.insert( QgsGrassVectorMap::TopoCentroidOut, "Centroid outside area" );
labels.insert( QgsGrassVectorMap::TopoCentroidDupl, "Duplicate centroid" );
categoryList.clear();
@ -104,15 +104,15 @@ QgsSymbolV2* QgsGrassEditRenderer::symbolForFeature( QgsFeature& feature, QgsRen
QgsDebugMsgLevel( QString( "fid = %1 symbolCode = %2" ).arg( feature.id() ).arg( symbolCode ), 3 );
QgsSymbolV2* symbol = 0;
if ( symbolCode == QgsGrassProvider::TopoPoint || symbolCode == QgsGrassProvider::TopoCentroidIn ||
symbolCode == QgsGrassProvider::TopoCentroidOut || symbolCode == QgsGrassProvider::TopoCentroidDupl ||
symbolCode == QgsGrassProvider::TopoNode0 || symbolCode == QgsGrassProvider::TopoNode1 ||
symbolCode == QgsGrassProvider::TopoNode2 )
if ( symbolCode == QgsGrassVectorMap::TopoPoint || symbolCode == QgsGrassVectorMap::TopoCentroidIn ||
symbolCode == QgsGrassVectorMap::TopoCentroidOut || symbolCode == QgsGrassVectorMap::TopoCentroidDupl ||
symbolCode == QgsGrassVectorMap::TopoNode0 || symbolCode == QgsGrassVectorMap::TopoNode1 ||
symbolCode == QgsGrassVectorMap::TopoNode2 )
{
symbol = mMarkerRenderer->symbolForFeature( feature, context );
}
else if ( symbolCode == QgsGrassProvider::TopoLine || symbolCode == QgsGrassProvider::TopoBoundary0 ||
symbolCode == QgsGrassProvider::TopoBoundary1 || symbolCode == QgsGrassProvider::TopoBoundary2 )
else if ( symbolCode == QgsGrassVectorMap::TopoLine || symbolCode == QgsGrassVectorMap::TopoBoundary0 ||
symbolCode == QgsGrassVectorMap::TopoBoundary1 || symbolCode == QgsGrassVectorMap::TopoBoundary2 )
{
symbol = mLineRenderer->symbolForFeature( feature, context );
}

View File

@ -248,14 +248,15 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
int type = 0;
int lid = 0;
QgsFeatureId featureId = 0;
QgsAbstractGeometryV2 *oldGeometry = 0;
#ifdef QGISDEBUG
if ( mSource->mEditing )
{
QgsDebugMsg( "newLids:" );
QgsDebugMsgLevel( "newLids:", 3 );
foreach ( int oldLid, mSource->mLayer->map()->newLids().keys() )
{
QgsDebugMsg( QString( "%1 -> %2" ).arg( oldLid ).arg( mSource->mLayer->map()->newLids().value( oldLid ) ) );
QgsDebugMsgLevel( QString( "%1 -> %2" ).arg( oldLid ).arg( mSource->mLayer->map()->newLids().value( oldLid ) ), 3 );
}
}
#endif
@ -263,24 +264,45 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
if ( filterById )
{
featureId = mRequest.filterFid();
lid = lidFormFid( mRequest.filterFid() );
lid = lidFromFid( mRequest.filterFid() );
QgsDebugMsg( QString( "featureId = %1 lid = %2" ).arg( featureId ).arg( lid ) );
if ( mSource->mLayer->map()->newLids().contains( lid ) )
if ( mSource->mEditing )
{
lid = mSource->mLayer->map()->newLids().value( lid );
QgsDebugMsg( QString( "line %1 rewritten -> real lid = %2" ).arg( lidFormFid( mRequest.filterFid() ) ).arg( lid ) );
// Undo needs the oldes version of geometry, but we also need topo_symbol, so we must read
// topo_symbol from map if the newLine exists read
if ( mSource->mLayer->map()->oldGeometries().contains( lid ) )
{
QgsDebugMsg( QString( "use old geometry for lid = %1" ).arg( lid ) );
oldGeometry = mSource->mLayer->map()->oldGeometries().value( lid );
if ( !oldGeometry )
{
QgsDebugMsg( "oldGeometry is null" );
}
}
if ( mSource->mLayer->map()->newLids().contains( lid ) )
{
// newLid may be 0 if line was deleted, in such case use only the old geometry, topo_symbol cannot be read
int newLid = mSource->mLayer->map()->newLids().value( lid );
QgsDebugMsg( QString( "use newLid = %1 -> lid = %2" ).arg( newLid ).arg( lid ) );
lid = newLid;
}
}
if ( !Vect_line_alive( mSource->map(), lid ) )
{
close();
mSource->mLayer->map()->unlockReadWrite();
return false;
}
type = Vect_read_line( mSource->map(), 0, 0, lid );
// TODO real cat when line/cat was rewritten?!
cat = catFormFid( mRequest.filterFid() );
QgsDebugMsg( QString( "lid = %1 cat = %2" ).arg( lid ).arg( cat ) );
if ( lid > 0 )
{
if ( !Vect_line_alive( mSource->map(), lid ) )
{
close();
mSource->mLayer->map()->unlockReadWrite();
return false;
}
type = Vect_read_line( mSource->map(), 0, 0, lid );
// TODO real cat when line/cat was rewritten?!
cat = catFromFid( mRequest.filterFid() );
QgsDebugMsg( QString( "lid = %1 cat = %2" ).arg( lid ).arg( cat ) );
}
}
else
{
@ -304,27 +326,35 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
break;
}
int realLid = mNextLid;
if ( mSource->mLayer->map()->newLids().contains( mNextLid ) )
int oldLid = mNextLid;
if ( mSource->mLayer->map()->oldLids().contains( mNextLid ) )
{
realLid = mSource->mLayer->map()->newLids().value( mNextLid );
QgsDebugMsg( QString( "line %1 rewritten -> realLid = %2" ).arg( mNextLid ).arg( realLid ) );
oldLid = mSource->mLayer->map()->oldLids().value( mNextLid );
QgsDebugMsg( QString( "mNextLid = %1 -> oldLid = %2" ).arg( mNextLid ).arg( oldLid ) );
}
if ( !Vect_line_alive( mSource->map(), realLid ) ) // should not be necessary for rewritten lines
if ( oldLid < 0 )
{
QgsDebugMsg( QString( "skip new feature oldLid = %1" ).arg( oldLid ) );
mNextLid++;
continue;
}
if ( !Vect_line_alive( mSource->map(), mNextLid ) ) // should not be necessary for rewritten lines
{
mNextLid++;
continue;
}
struct line_cats *cats = Vect_new_cats_struct();
int tmpType = Vect_read_line( mSource->map(), 0, cats, realLid );
int tmpType = Vect_read_line( mSource->map(), 0, cats, mNextLid );
if ( cats->n_cats == 0 )
{
lid = realLid;
lid = mNextLid;
type = tmpType;
cat = 0;
featureId = makeFeatureId( mNextLid, cat );
featureId = makeFeatureId( oldLid, cat );
mNextLid++;
}
else
@ -345,10 +375,10 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
}
else
{
lid = realLid;
lid = mNextLid;
type = tmpType;
cat = cats->cat[mNextCidx];
featureId = makeFeatureId( mNextLid, cat );
featureId = makeFeatureId( oldLid, cat );
mNextCidx++;
}
}
@ -417,19 +447,22 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
break;
}
}
if ( lid == 0 || lid > mSource->mLayer->map()->numLines() )
if ( !oldGeometry )
{
QgsDebugMsg( QString( "lid = %1 -> close" ).arg( lid ) );
close();
mSource->mLayer->map()->unlockReadWrite();
return false; // No more features
}
if ( type == 0 ) // should not happen
{
QgsDebugMsg( "unknown type" );
close();
mSource->mLayer->map()->unlockReadWrite();
return false;
if ( lid == 0 || lid > mSource->mLayer->map()->numLines() )
{
QgsDebugMsg( QString( "lid = %1 -> close" ).arg( lid ) );
close();
mSource->mLayer->map()->unlockReadWrite();
return false; // No more features
}
if ( type == 0 ) // should not happen
{
QgsDebugMsg( "unknown type" );
close();
mSource->mLayer->map()->unlockReadWrite();
return false;
}
}
QgsDebugMsgLevel( QString( "lid = %1 type = %2 cat = %3 fatureId = %4" ).arg( lid ).arg( type ).arg( cat ).arg( featureId ), 3 );
@ -440,36 +473,22 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
// TODO ???
#if 0
// Changed geometry are always read from cache
if ( mSource->mEditing && mSource->mChangedFeatures.contains( mRequest.filterFid() ) )
if ( oldGeometry )
{
QgsDebugMsg( QString( "filterById = %1 mRequest.filterFid() = %2 mSource->mChangedFeatures.size() = %3" ).arg( filterById ).arg( mRequest.filterFid() ).arg( mSource->mChangedFeatures.size() ) );
QgsFeature f = mSource->mChangedFeatures.value( mRequest.filterFid() );
QgsDebugMsg( QString( "return features from mChangedFeatures id = %1" ).arg( f.id() ) );
feature.setFeatureId( f.id() );
feature.initAttributes( mSource->mFields.count() );
feature.setFields( &( mSource->mFields ) ); // allow name-based attribute lookups
feature.setAttributes( f.attributes() );
feature.setGeometry( new QgsGeometry( *( f.geometry() ) ) );
feature.setValid( true );
mSource->mLayer->map()->unlockReadWrite();
return true;
feature.setGeometry( new QgsGeometry( oldGeometry->clone() ) );
}
else
{
setFeatureGeometry( feature, lid, type );
}
#endif
setFeatureGeometry( feature, lid, type );
}
if ( !QgsGrassProvider::isTopoType( mSource->mLayerType ) )
{
QgsGrassProvider::TopoSymbol symbol = QgsGrassProvider::TopoUndefined;
if ( mSource->mEditing )
QgsGrassVectorMap::TopoSymbol symbol = QgsGrassVectorMap::TopoUndefined;
if ( mSource->mEditing && lid > 0 )
{
symbol = topoSymbol( lid, type );
symbol = mSource->mLayer->map()->topoSymbol( lid );
}
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
@ -528,9 +547,6 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
return true;
}
bool QgsGrassFeatureIterator::rewind()
{
if ( mClosed )
@ -569,27 +585,7 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
QgsAbstractGeometryV2 *geometry = 0;
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) )
{
if ( mSource->mEditing )
{
// Use original geometry because QgsVectorLayerUndoCommandChangeGeometry::undo() needs that
if ( mSource->mLayer->map()->oldLids().contains( id ) )
{
int oldLid = mSource->mLayer->map()->oldLids().value( id );
QgsDebugMsg( QString( "oldLid = %1 -> use old geometry" ).arg( oldLid ) );
if ( mSource->mLayer->map()->oldGeometries().contains( oldLid ) )
{
geometry = mSource->mLayer->map()->oldGeometries().value( oldLid )->clone();
}
else
{
QgsDebugMsg( "geometry not found in oldGeometries" );
}
}
}
if ( !geometry )
{
geometry = mSource->mLayer->map()->lineGeometry( id );
}
geometry = mSource->mLayer->map()->lineGeometry( id );
}
else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE )
{
@ -613,59 +609,28 @@ QgsFeatureId QgsGrassFeatureIterator::makeFeatureId( int grassId, int cat )
return ( QgsFeatureId )grassId * 1000000000 + cat;
}
int QgsGrassFeatureIterator::lidFormFid( QgsFeatureId fid )
int QgsGrassFeatureIterator::lidFromFid( QgsFeatureId fid )
{
// New features have negative fid, we take such fid as (still negative) lid
// it is only used for mapping from fid to real lid
if ( FID_IS_NEW( fid ) )
{
return fid;
}
return fid / 1000000000;
}
int QgsGrassFeatureIterator::catFormFid( QgsFeatureId fid )
int QgsGrassFeatureIterator::catFromFid( QgsFeatureId fid )
{
if ( FID_IS_NEW( fid ) )
{
// TODO: keep track of cats for new features
return 0;
}
return fid % 1000000000;
}
QgsGrassProvider::TopoSymbol QgsGrassFeatureIterator::topoSymbol( int lid, int type )
{
QgsGrassProvider::TopoSymbol symbol = QgsGrassProvider::TopoUndefined;
if ( type == GV_POINT )
{
symbol = QgsGrassProvider::TopoPoint;
}
else if ( type == GV_CENTROID )
{
int area = Vect_get_centroid_area( mSource->map(), lid );
if ( area == 0 )
symbol = QgsGrassProvider::TopoCentroidOut;
else if ( area > 0 )
symbol = QgsGrassProvider::TopoCentroidIn;
else
symbol = QgsGrassProvider::TopoCentroidDupl; /* area < 0 */
}
else if ( type == GV_LINE )
{
symbol = QgsGrassProvider::TopoLine;
}
else if ( type == GV_BOUNDARY )
{
int left, right;
Vect_get_line_areas( mSource->map(), lid, &left, &right );
if ( left != 0 && right != 0 )
{
symbol = QgsGrassProvider::TopoBoundary2;
}
else if ( left == 0 && right == 0 )
{
symbol = QgsGrassProvider::TopoBoundary0;
}
else
{
symbol = QgsGrassProvider::TopoBoundary1;
}
}
QgsDebugMsgLevel( QString( "lid = %1 type = %2 symbol = %3" ).arg( lid ).arg( type ).arg( symbol ), 3 );
return symbol;
}
void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassProvider::TopoSymbol symbol )
void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassVectorMap::TopoSymbol symbol )
{
QgsDebugMsgLevel( QString( "setFeatureAttributes cat = %1" ).arg( cat ), 3 );
QgsAttributeList attlist;
@ -684,7 +649,7 @@ void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature
return setFeatureAttributes( cat, feature, attlist, symbol );
}
void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList& attlist, QgsGrassProvider::TopoSymbol symbol )
void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList& attlist, QgsGrassVectorMap::TopoSymbol symbol )
{
QgsDebugMsgLevel( QString( "setFeatureAttributes cat = %1 symbol = %2" ).arg( cat ).arg( symbol ), 3 );
int nFields = mSource->mLayer->fields().size();

View File

@ -88,10 +88,10 @@ class QgsGrassFeatureIterator : public QObject, public QgsAbstractFeatureIterato
static QgsFeatureId makeFeatureId( int grassId, int cat );
// Get GRASS line id from QGIS fid
static int lidFormFid( QgsFeatureId fid );
static int lidFromFid( QgsFeatureId fid );
// Get GRASS cat from QGIS fid
static int catFormFid( QgsFeatureId fid );
static int catFromFid( QgsFeatureId fid );
public slots:
/** Cancel iterator, iterator will be closed on next occasion, probably when next getFeature() gets called.
@ -115,19 +115,14 @@ class QgsGrassFeatureIterator : public QObject, public QgsAbstractFeatureIterato
* @param feature
* @param cat category number
*/
void setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassProvider::TopoSymbol symbol );
void setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassVectorMap::TopoSymbol symbol );
/** Set feature attributes.
* @param feature
* @param cat category number
* @param attlist a list containing the index number of the fields to set
*/
void setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList & attlist, QgsGrassProvider::TopoSymbol symbol );
/** Get topology symbol code
* @param lid line or area number
* @param type geometry type */
QgsGrassProvider::TopoSymbol topoSymbol( int lid, int type );
void setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList & attlist, QgsGrassVectorMap::TopoSymbol symbol );
/** Canceled -> close when possible */
bool mCanceled;

View File

@ -25,6 +25,9 @@
#include "qgsdataprovider.h"
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgslinestringv2.h"
#include "qgspointv2.h"
#include "qgspolygonv2.h"
#include "qgsrectangle.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayereditbuffer.h"
@ -238,8 +241,7 @@ int QgsGrassProvider::capabilities() const
// for now, only one map may be edited at time
if ( mEditBuffer || ( mLayer && mLayer->map() && !mLayer->map()->isEdited() ) )
{
//return AddFeatures | DeleteFeatures | ChangeAttributeValues | AddAttributes | DeleteAttributes | ChangeGeometries;
return ChangeGeometries;
return AddFeatures | DeleteFeatures | ChangeGeometries ;
}
return 0;
}
@ -1265,7 +1267,12 @@ void QgsGrassProvider::startEditing( QgsVectorLayer *vectorLayer )
mLayer->map()->startEdit();
mEditBuffer = vectorLayer->editBuffer();
connect( mEditBuffer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry & ) ), SLOT( bufferGeometryChanged( QgsFeatureId, QgsGeometry & ) ) );
connect( mEditBuffer, SIGNAL( featureAdded( QgsFeatureId ) ), SLOT( onFeatureAdded( QgsFeatureId ) ) );
connect( mEditBuffer, SIGNAL( featureDeleted( QgsFeatureId ) ), SLOT( onFeatureDeleted( QgsFeatureId ) ) );
connect( mEditBuffer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry & ) ), SLOT( onGeometryChanged( QgsFeatureId, QgsGeometry & ) ) );
connect( mEditBuffer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant & ) ), SLOT( onAttributeValueChanged( QgsFeatureId, int, const QVariant & ) ) );
connect( mEditBuffer, SIGNAL( attributeAdded( int ) ), SLOT( onAttributeAdded( int ) ) );
connect( mEditBuffer, SIGNAL( attributeDeleted( int ) ), SLOT( onAttributeDeleted( int ) ) );
connect( vectorLayer, SIGNAL( beforeCommitChanges() ), SLOT( onBeforeCommitChanges() ) );
connect( vectorLayer, SIGNAL( editingStopped() ), SLOT( onEditingStopped() ) );
@ -1274,9 +1281,221 @@ void QgsGrassProvider::startEditing( QgsVectorLayer *vectorLayer )
QgsDebugMsg( "edit started" );
}
void QgsGrassProvider::bufferGeometryChanged( QgsFeatureId fid, QgsGeometry &geom )
void QgsGrassProvider::setPoints( struct line_pnts *points, const QgsAbstractGeometryV2 * geometry )
{
int oldLid = QgsGrassFeatureIterator::lidFormFid( fid );
if ( !points )
{
return;
}
Vect_reset_line( points );
if ( !geometry )
{
return;
}
if ( geometry->wkbType() == QgsWKBTypes::Point )
{
const QgsPointV2* point = dynamic_cast<const QgsPointV2*>( geometry );
if ( point )
{
Vect_append_point( points, point->x(), point->y(), point->z() );
QgsDebugMsg( QString( "x = %1 y = %2" ).arg( point->x() ).arg( point->y() ) );
}
}
else if ( geometry->wkbType() == QgsWKBTypes::LineString )
{
const QgsLineStringV2* lineString = dynamic_cast<const QgsLineStringV2*>( geometry );
if ( lineString )
{
for ( int i = 0; i < lineString->numPoints(); i++ )
{
QgsPointV2 point = lineString->pointN( i );
Vect_append_point( points, point.x(), point.y(), point.z() );
}
}
}
else if ( geometry->wkbType() == QgsWKBTypes::Polygon )
{
const QgsPolygonV2* polygon = dynamic_cast<const QgsPolygonV2*>( geometry );
if ( polygon && polygon->exteriorRing() )
{
QList<QgsPointV2> pointsList;
polygon->exteriorRing()->points( pointsList );
Q_FOREACH ( QgsPointV2 point, pointsList )
{
Vect_append_point( points, point.x(), point.y(), point.z() );
}
}
}
else
{
QgsDebugMsg( "unknown type : " + geometry->geometryType() );
}
}
void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
{
// fid is negative for new features
int lid = QgsGrassFeatureIterator::lidFromFid( fid );
int cat = QgsGrassFeatureIterator::catFromFid( fid );
QgsDebugMsg( QString( "fid = %1 lid = %2 cat = %3" ).arg( fid ).arg( lid ).arg( cat ) );
const QgsAbstractGeometryV2 *geometry = 0;
if ( FID_IS_NEW( fid ) )
{
if ( !mEditBuffer->addedFeatures().contains( fid ) )
{
QgsDebugMsg( "the feature is missing in buffer addedFeatures :" );
Q_FOREACH ( QgsFeatureId id, mEditBuffer->addedFeatures().keys() )
{
QgsDebugMsg( QString( "addedFeatures : id = %1" ).arg( id ) );
}
return;
}
QgsFeature feature = mEditBuffer->addedFeatures().value( fid );
if ( feature.geometry() )
{
geometry = feature.geometry()->geometry();
}
}
else // old deleted feature undo
{
// If it is not new feature, we should have the geometry in oldGeometries
if ( mLayer->map()->oldGeometries().contains( lid ) )
{
geometry = mLayer->map()->oldGeometries().value( lid );
}
else
{
QgsDebugMsg( "geometry of old, previously deleted feature not found" );
}
}
if ( !geometry )
{
QgsDebugMsg( "geometry is null" );
}
else
{
struct line_pnts *points = Vect_new_line_struct();
struct line_cats *cats = Vect_new_cats_struct();
setPoints( points, geometry );
// TODO: get also old type if it is feature previously deleted
int type = 0;
QgsWKBTypes::Type wkbType = QgsWKBTypes::flatType( geometry->wkbType() );
if ( wkbType == QgsWKBTypes::Point )
{
type = GV_POINT;
}
else if ( wkbType == QgsWKBTypes::LineString )
{
type = GV_LINE;
}
else if ( wkbType == QgsWKBTypes::Polygon )
{
type = GV_BOUNDARY;
}
else
{
QgsDebugMsg( QString( "unknown type %1" ).arg( wkbType ) );
}
if ( cat > 0 )
{
// TODO: orig field, maybe different
int field = mLayerField;
Vect_cat_set( cats, field, cat );
}
if ( type > 0 && points->n_points > 0 )
{
mLayer->map()->lockReadWrite();
int newLid = Vect_write_line( map(), type, points, cats );
mLayer->map()->unlockReadWrite();
QgsDebugMsg( QString( "newLine = %1" ).arg( newLid ) );
// fid may be new (negative) or old, if this is delete undo
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
mLayer->map()->oldLids()[newLid] = oldLid;
mLayer->map()->newLids()[oldLid] = newLid;
QgsDebugMsg( QString( "oldLid = %1 newLine = %2" ).arg( oldLid ).arg( newLid ) );
QgsDebugMsg( QString( "oldLids : %1 -> %2" ).arg( newLid ).arg( oldLid ) );
mLayer->map()->oldLids()[newLid] = oldLid;
QgsDebugMsg( QString( "newLids : %1 -> %2" ).arg( oldLid ).arg( newLid ) );
mLayer->map()->newLids()[oldLid] = newLid;
if ( FID_IS_NEW( fid ) )
{
// Set topo symbol attribute
int symbol = mLayer->map()->topoSymbol( newLid );
QgsDebugMsg( QString( "symbol = %1" ).arg( symbol ) );
// TODO attribute index
int idx = mLayer->fields().size() - 1;
QgsFeatureMap & addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
addedFeatures[fid].setAttribute( idx, QVariant( symbol ) );
}
}
Vect_destroy_line_struct( points );
Vect_destroy_cats_struct( cats );
}
}
void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )
{
QgsDebugMsg( QString( "fid = %1" ).arg( fid ) );
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
int realLine = oldLid;
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
{
realLine = mLayer->map()->newLids().value( oldLid );
}
QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3" ).arg( fid ).arg( oldLid ).arg( realLine ) );
// store only the first original geometry if it is not new feature, changed geometries are stored in the buffer
if ( oldLid > 0 && !mLayer->map()->oldGeometries().contains( oldLid ) )
{
QgsAbstractGeometryV2 *geometry = mLayer->map()->lineGeometry( oldLid );
if ( geometry )
{
QgsDebugMsg( QString( "save old geometry of oldLid = %1" ).arg( oldLid ) );
mLayer->map()->oldGeometries().insert( oldLid, geometry );
}
else
{
QgsDebugMsg( QString( "cannot read geometry of oldLid = %1" ).arg( oldLid ) );
}
}
mLayer->map()->lockReadWrite();
G_TRY
{
Vect_delete_line( map(), realLine );
// oldLids are maping to the very first, original version (used by undo)
int oldestLid = oldLid;
if ( mLayer->map()->oldLids().contains( oldLid ) )
{
oldestLid = mLayer->map()->oldLids().value( oldLid );
}
QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2" ).arg( oldLid ).arg( oldestLid ) );
QgsDebugMsg( QString( "newLids : %1 -> 0" ).arg( oldestLid ) );
mLayer->map()->newLids()[oldestLid] = 0;
}
G_CATCH( QgsGrass::Exception &e )
{
QgsDebugMsg( QString( "Cannot delete line : %1" ).arg( e.what() ) );
}
mLayer->map()->unlockReadWrite();
}
void QgsGrassProvider::onGeometryChanged( QgsFeatureId fid, QgsGeometry &geom )
{
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
int realLine = oldLid;
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
{
@ -1287,52 +1506,81 @@ void QgsGrassProvider::bufferGeometryChanged( QgsFeatureId fid, QgsGeometry &geo
struct line_pnts *points = Vect_new_line_struct();
struct line_cats *cats = Vect_new_cats_struct();
int type = Vect_read_line( map(), points, cats, realLine );
QgsDebugMsg( QString( "type = %1 n_points = %2" ).arg( type ).arg( points->n_points ) );
// store only the first original geometry, changed geometries are stored in the buffer
if ( !mLayer->map()->oldGeometries().contains( oldLid ) )
int type;
G_TRY
{
QgsAbstractGeometryV2 *geometry = mLayer->map()->lineGeometry( oldLid );
mLayer->map()->oldGeometries().insert( oldLid, geometry );
type = Vect_read_line( map(), points, cats, realLine );
}
if ( type == GV_POINT || type == GV_CENTROID )
G_CATCH( QgsGrass::Exception &e )
{
QgsPoint point = geom.asPoint();
points->x[0] = point.x();
points->y[0] = point.y();
QgsDebugMsg( QString( "x = %1 y = %2" ).arg( point.x() ).arg( point.y() ) );
}
else if ( type == GV_LINE || type == GV_BOUNDARY )
{
QgsPolyline polyline = geom.asPolyline();
for ( int i = 0; i < points->n_points; i++ )
{
points->x[i] = polyline.value( i ).x();
points->y[i] = polyline.value( i ).y();
}
}
else
{
QgsDebugMsg( "unknown type" );
QgsDebugMsg( QString( "Cannot read line : %1" ).arg( e.what() ) );
Vect_destroy_line_struct( points );
Vect_destroy_cats_struct( cats );
return;
}
QgsDebugMsg( QString( "type = %1 n_points = %2" ).arg( type ).arg( points->n_points ) );
// store only the first original geometry if it is not new feature, changed geometries are stored in the buffer
if ( oldLid > 0 && !mLayer->map()->oldGeometries().contains( oldLid ) )
{
QgsAbstractGeometryV2 *geometry = mLayer->map()->lineGeometry( oldLid );
if ( geometry )
{
QgsDebugMsg( QString( "save old geometry of oldLid = %1" ).arg( oldLid ) );
mLayer->map()->oldGeometries().insert( oldLid, geometry );
}
else
{
QgsDebugMsg( QString( "cannot read geometry of oldLid = %1" ).arg( oldLid ) );
}
}
setPoints( points, geom.geometry() );
mLayer->map()->lockReadWrite();
// Vect_rewrite_line may delete/write the line with a new id
int newLid = Vect_rewrite_line( map(), realLine, type, points, cats );
G_TRY
{
newLid = Vect_rewrite_line( map(), realLine, type, points, cats );
// oldLids are maping to the very first, original version (used by undo)
int oldestLid = oldLid;
if ( mLayer->map()->oldLids().contains( oldLid ) )
{
oldestLid = mLayer->map()->oldLids().value( oldLid );
}
QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2 newLine = %3" ).arg( oldLid ).arg( oldestLid ).arg( newLid ) );
QgsDebugMsg( QString( "oldLids : %1 -> %2" ).arg( newLid ).arg( oldestLid ) );
mLayer->map()->oldLids()[newLid] = oldestLid;
QgsDebugMsg( QString( "newLids : %1 -> %2" ).arg( oldestLid ).arg( newLid ) );
mLayer->map()->newLids()[oldestLid] = newLid;
}
G_CATCH( QgsGrass::Exception &e )
{
QgsDebugMsg( QString( "Cannot write line : %1" ).arg( e.what() ) );
}
mLayer->map()->unlockReadWrite();
QgsDebugMsg( QString( "oldLid = %1 newLine = %2" ).arg( oldLid ).arg( newLid ) );
// oldLids are maping to the very first, original version (used by undo)
int oldestLid = oldLid;
if ( mLayer->map()->oldLids().contains( oldLid ) )
{
oldestLid = mLayer->map()->oldLids().value( oldLid );
}
mLayer->map()->oldLids()[newLid] = oldestLid;
mLayer->map()->newLids()[oldLid] = newLid;
Vect_destroy_line_struct( points );
Vect_destroy_cats_struct( cats );
}
void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
{
QgsDebugMsg( QString( "fid = %1 idx = %2 value = %3" ).arg( fid ).arg( idx ).arg( value.toString() ) );
}
void QgsGrassProvider::onAttributeAdded( int idx )
{
QgsDebugMsg( QString( "idx = %1" ).arg( idx ) );
}
void QgsGrassProvider::onAttributeDeleted( int idx )
{
QgsDebugMsg( QString( "idx = %1" ).arg( idx ) );
}
void QgsGrassProvider::onUndoIndexChanged( int index )

View File

@ -57,21 +57,6 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
Q_OBJECT
public:
enum TopoSymbol
{
TopoUndefined = 0,
TopoPoint,
TopoLine,
TopoBoundary0,
TopoBoundary1,
TopoBoundary2,
TopoCentroidIn,
TopoCentroidOut,
TopoCentroidDupl,
TopoNode0,
TopoNode1,
TopoNode2
};
QgsGrassProvider( QString uri = QString() );
@ -439,7 +424,12 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
};
public slots:
void bufferGeometryChanged( QgsFeatureId fid, QgsGeometry &geom );
void onFeatureAdded( QgsFeatureId fid );
void onFeatureDeleted( QgsFeatureId fid );
void onGeometryChanged( QgsFeatureId fid, QgsGeometry &geom );
void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
void onAttributeAdded( int idx );
void onAttributeDeleted( int idx );
void onBeforeCommitChanges();
void onEditingStopped();
void onUndoIndexChanged( int index );
@ -495,6 +485,8 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
void setTopoFields();
void setPoints( struct line_pnts *points, const QgsAbstractGeometryV2 * geometry );
/** Fields used for topo layers */
QgsFields mTopoFields;

View File

@ -683,3 +683,47 @@ QgsGrassVectorMap * QgsGrassVectorMapStore::openMap( const QgsGrassObject & gras
mMutex.unlock();
return map;
}
QgsGrassVectorMap::TopoSymbol QgsGrassVectorMap::topoSymbol( int lid )
{
int type = Vect_read_line( mMap, 0, 0, lid );
TopoSymbol symbol = TopoUndefined;
if ( type == GV_POINT )
{
symbol = TopoPoint;
}
else if ( type == GV_CENTROID )
{
int area = Vect_get_centroid_area( mMap, lid );
if ( area == 0 )
symbol = TopoCentroidOut;
else if ( area > 0 )
symbol = TopoCentroidIn;
else
symbol = TopoCentroidDupl; /* area < 0 */
}
else if ( type == GV_LINE )
{
symbol = TopoLine;
}
else if ( type == GV_BOUNDARY )
{
int left, right;
Vect_get_line_areas( mMap, lid, &left, &right );
if ( left != 0 && right != 0 )
{
symbol = TopoBoundary2;
}
else if ( left == 0 && right == 0 )
{
symbol = TopoBoundary0;
}
else
{
symbol = TopoBoundary1;
}
}
QgsDebugMsgLevel( QString( "lid = %1 type = %2 symbol = %3" ).arg( lid ).arg( type ).arg( symbol ), 3 );
return symbol;
}

View File

@ -29,6 +29,22 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
{
Q_OBJECT
public:
enum TopoSymbol
{
TopoUndefined = 0,
TopoPoint,
TopoLine,
TopoBoundary0,
TopoBoundary1,
TopoBoundary2,
TopoCentroidIn,
TopoCentroidOut,
TopoCentroidDupl,
TopoNode0,
TopoNode1,
TopoNode2
};
QgsGrassVectorMap( const QgsGrassObject & grassObject );
~QgsGrassVectorMap();
@ -111,6 +127,11 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
/** Map descripton for debugging */
QString toString();
/** Get topology symbol code
* @param lid line or area number
* @param type geometry type */
TopoSymbol topoSymbol( int lid );
signals:
/** Ask all iterators to cancel iteration when possible. Connected to iterators with
* Qt::DirectConnection (non blocking) */