void QgsMapToolNodeTool::createMovingRubberBands() { int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); Q_ASSERT( mSelectedFeature ); QgsVectorLayer *vlayer = mSelectedFeature->vlayer(); Q_ASSERT( vlayer ); QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap(); QgsGeometry* geometry = mSelectedFeature->geometry(); int beforeVertex, afterVertex; int lastRubberBand = 0; int vertex; for ( int i = 0; i < vertexMap.size(); i++ ) { // create rubberband if ( vertexMap[i]->isSelected() && !vertexMap[i]->isInRubberBand() ) { geometry->adjacentVertices( i, beforeVertex, afterVertex ); vertex = i; while ( beforeVertex != -1 ) { // move forward NOTE: end if whole cycle is selected if ( vertexMap[beforeVertex]->isSelected() && beforeVertex != i ) // and take care of cycles { vertex = beforeVertex; geometry->adjacentVertices( vertex, beforeVertex, afterVertex ); } else { // break if cycle is found break; } } // we have first vertex of moving part // create rubberband and set default paramaters QgsRubberBand* rb = new QgsRubberBand( mCanvas, QGis::Line ); rb->setWidth( 2 ); rb->setColor( Qt::blue ); int index = 0; if ( beforeVertex != -1 ) // adding first point which is not moving { rb->addPoint( toMapCoordinates( vlayer, vertexMap[beforeVertex]->point() ), false ); vertexMap[beforeVertex]->setRubberBandValues( true, lastRubberBand, index ); index++; } while ( vertex != -1 && vertexMap[vertex]->isSelected() && !vertexMap[vertex]->isInRubberBand() ) { // topology rubberband creation if needed if ( topologicalEditing ) { createTopologyRubberBands( vlayer, vertexMap, vertex ); } // adding point which will be moved rb->addPoint( toMapCoordinates( vlayer, vertexMap[vertex]->point() ), false ); // setting values about added vertex vertexMap[vertex]->setRubberBandValues( true, lastRubberBand, index ); index++; geometry->adjacentVertices( vertex, beforeVertex, vertex ); } if ( vertex != -1 && !vertexMap[vertex]->isSelected() ) // add last point not moving if exists { rb->addPoint( toMapCoordinates( vlayer, vertexMap[vertex]->point() ), true ); vertexMap[vertex]->setRubberBandValues( true, lastRubberBand, index ); index++; } mRubberBands.append( rb ); lastRubberBand++; } } }
void QgsMapToolNodeTool::createTopologyRubberBands( QgsVectorLayer* vlayer, const QList<QgsVertexEntry*> &vertexMap, int vertex ) { QMultiMap<double, QgsSnappingResult> currentResultList; QgsGeometry *geometry = mSelectedFeature->geometry(); // snap from current vertex currentResultList.clear(); vlayer->snapWithContext( vertexMap[vertex]->point(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex ); QMultiMap<double, QgsSnappingResult>::iterator resultIt = currentResultList.begin(); for ( ; resultIt != currentResultList.end(); ++resultIt ) { // move all other if ( mSelectedFeature->featureId() != resultIt.value().snappedAtGeometry ) { if ( mTopologyMovingVertexes.contains( resultIt.value().snappedAtGeometry ) ) { if ( mTopologyMovingVertexes[resultIt.value().snappedAtGeometry]->contains( resultIt.value().snappedVertexNr ) ) { // skip vertex already exists in some rubberband continue; } } QgsRubberBand* trb = new QgsRubberBand( mCanvas, QGis::Line ); mTopologyRubberBand.append( trb ); int rbId = mTopologyRubberBand.size() - 1; trb->setWidth( 1 ); trb->setColor( Qt::red ); int tVertex = resultIt.value().snappedVertexNr; int tVertexBackup = -1, tVertexAfter = -1; int tVertexFirst = tVertex; // vertex number to check for cycling QgsFeature topolFeature; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( resultIt.value().snappedAtGeometry ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( topolFeature ); QgsGeometry* topolGeometry = topolFeature.geometry(); while ( tVertex != -1 ) // looking for first vertex to rubberband { tVertexBackup = tVertex; topolGeometry->adjacentVertices( tVertex, tVertex, tVertexAfter ); if ( tVertex == -1 || tVertex == tVertexFirst ) break; // check if this is not first vertex of the feature or cycling error // if closest vertex is not from selected feature or is not selected end double dist; QgsPoint point = topolGeometry->vertexAt( tVertex ); int at, before, after; geometry->closestVertex( point, at, before, after, dist ); if ( dist > ZERO_TOLERANCE || !vertexMap[at]->isSelected() ) // problem with double precision { break; // found first vertex } } int movingPointIndex = 0; Vertexes* movingPoints = new Vertexes(); Vertexes* addedPoints = new Vertexes(); if ( mTopologyMovingVertexes.contains( resultIt.value().snappedAtGeometry ) ) { addedPoints = mTopologyMovingVertexes[ resultIt.value().snappedAtGeometry ]; } if ( tVertex == -1 ) // adding first point if needed { tVertex = tVertexBackup; } else { trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) ); if ( tVertex == tVertexFirst ) // cycle first vertex need to be added also { movingPoints->insert( movingPointIndex ); } movingPointIndex = 1; topolGeometry->adjacentVertices( tVertex, tVertexAfter, tVertex ); } while ( tVertex != -1 ) { // if closest vertex is not from selected feature or is not selected end double dist; QgsPoint point = topolGeometry->vertexAt( tVertex ); int at, before, after; geometry->closestVertex( point, at, before, after, dist ); // find first no matching vertex if ( dist > ZERO_TOLERANCE || !vertexMap[at]->isSelected() ) // problem with double precision { trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) ); break; // found first vertex } else // add moving point to rubberband { if ( addedPoints->contains( tVertex ) ) break; // just preventing to circle trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) ); movingPoints->insert( movingPointIndex ); movingPointIndex++; addedPoints->insert( tVertex ); } topolGeometry->adjacentVertices( tVertex, tVertexAfter, tVertex ); } mTopologyMovingVertexes.insert( resultIt.value().snappedAtGeometry, addedPoints ); mTopologyRubberBandVertexes.insert( rbId, movingPoints ); } } }