Beispiel #1
0
void QgsMapToolRotateFeature::canvasReleaseEvent( QMouseEvent * e )
{
    Q_UNUSED( e );
    if ( !mRubberBand )
    {
        return;
    }

    QgsVectorLayer* vlayer = currentVectorLayer();
    if ( !vlayer )
    {
        return;
    }

    //calculations for affine transformation
    double angle = -1 * mRotation * ( PI / 180 );
    QgsPoint anchorPoint = toLayerCoordinates( vlayer, mStartPointMapCoords );
    double a = cos( angle );
    double b = -1 * sin( angle );
    double c = anchorPoint.x() - cos( angle ) * anchorPoint.x() + sin( angle ) * anchorPoint.y();
    double d = sin( angle );
    double ee = cos( angle );
    double f = anchorPoint.y() - sin( angle ) * anchorPoint.x() - cos( angle ) * anchorPoint.y();

    vlayer->beginEditCommand( tr( "Features Rotated" ) );

    int start;
    if ( vlayer->geometryType() == 2 )
    {
        start = 1;
    }
    else
    {
        start = 0;
    }

    int i = 0;
    foreach ( QgsFeatureId id, mRotatedFeatures )
    {
        QgsFeature feat;
        vlayer->getFeatures( QgsFeatureRequest().setFilterFid( id ) ).nextFeature( feat );
        QgsGeometry* geom = feat.geometry();
        i = start;

        QgsPoint vertex = geom->vertexAt( i );
        while ( vertex != QgsPoint( 0, 0 ) )
        {
            double newX = a * vertex.x() + b * vertex.y() + c;
            double newY = d * vertex.x() + ee * vertex.y() + f;

            vlayer->moveVertex( newX, newY, id, i );
            i = i + 1;
            vertex = geom->vertexAt( i );
        }

    }
void QgsMapToolRotateFeature::applyRotation( double rotation )
{
  mRotation = rotation;
  mRotationActive = false;

  QgsVectorLayer *vlayer = currentVectorLayer();
  if ( !vlayer )
  {
    deleteRubberband();
    notifyNotVectorLayer();
    return;
  }

  //calculations for affine transformation
  double angle = -1 * mRotation * ( M_PI / 180 );
  QgsPointXY anchorPoint = toLayerCoordinates( vlayer, mStartPointMapCoords );
  double a = std::cos( angle );
  double b = -1 * std::sin( angle );
  double c = anchorPoint.x() - std::cos( angle ) * anchorPoint.x() + std::sin( angle ) * anchorPoint.y();
  double d = std::sin( angle );
  double ee = std::cos( angle );
  double f = anchorPoint.y() - std::sin( angle ) * anchorPoint.x() - std::cos( angle ) * anchorPoint.y();

  vlayer->beginEditCommand( tr( "Features Rotated" ) );

  int start;
  if ( vlayer->geometryType() == 2 )
  {
    start = 1;
  }
  else
  {
    start = 0;
  }

  int i = 0;
  Q_FOREACH ( QgsFeatureId id, mRotatedFeatures )
  {
    QgsFeature feat;
    vlayer->getFeatures( QgsFeatureRequest().setFilterFid( id ) ).nextFeature( feat );
    QgsGeometry geom = feat.geometry();
    i = start;

    QgsPointXY vertex = geom.vertexAt( i );
    while ( vertex != QgsPointXY( 0, 0 ) )
    {
      double newX = a * vertex.x() + b * vertex.y() + c;
      double newY = d * vertex.x() + ee * vertex.y() + f;

      vlayer->moveVertex( newX, newY, id, i );
      i = i + 1;
      vertex = geom.vertexAt( i );
    }

  }
Beispiel #3
0
    void visitData( const IData& d ) override
    {
      QgsFeatureId id = d.getIdentifier();
      QgsGeometry* geom = mLocator->mGeoms.value( id );
      QgsPoint pt;
      int afterVertex;
      double sqrDist = geom->closestSegmentWithContext( mSrcPoint, pt, afterVertex, nullptr, POINT_LOC_EPSILON );
      if ( sqrDist < 0 )
        return;

      QgsPoint edgePoints[2];
      edgePoints[0] = geom->vertexAt( afterVertex - 1 );
      edgePoints[1] = geom->vertexAt( afterVertex );
      QgsPointLocator::Match m( QgsPointLocator::Edge, mLocator->mLayer, id, sqrt( sqrDist ), pt, afterVertex - 1, edgePoints );
      // in range queries the filter may reject some matches
      if ( mFilter && !mFilter->acceptMatch( m ) )
        return;

      if ( !mBest.isValid() || m.distance() < mBest.distance() )
        mBest = m;
    }
QgsPoint QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, const QgsGeometry& lineGeom ) const
{
  QgsPoint p( x, y );
  QgsPoint minDistPoint;
  int afterVertexNr;
  lineGeom.closestSegmentWithContext( p, minDistPoint, afterVertexNr );

  int beforeVertexNr = afterVertexNr - 1;
  QgsPoint beforeVertex = lineGeom.vertexAt( beforeVertexNr );
  QgsPoint afterVertex = lineGeom.vertexAt( afterVertexNr );

  //get normal vector
  double dx = afterVertex.x() - beforeVertex.x();
  double dy = afterVertex.y() - beforeVertex.y();
  double normalX = -dy;
  double normalY = dx;
  double normalLength = sqrt( normalX * normalX + normalY * normalY );
  normalX *= ( dist / normalLength );
  normalY *= ( dist / normalLength );

  double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control
  Q_UNUSED( debugLength );
  return QgsPoint( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side
}
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 );
    }
  }
}