예제 #1
0
void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
{
  QgsDebugCall;

  mClicked = true;
  mPressCoordinates = e->pos();
  if ( !mSelectedFeature )
  {
    QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
    if ( !vlayer )
      return;

    mSelectAnother = false;
    QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex | QgsPointLocator::Edge );
    if ( !m.isValid() )
    {
      emit messageEmitted( tr( "could not snap to a segment on the current layer." ) );
      return;
    }

    // remove previous warning
    emit messageDiscarded();

    mSelectedFeature = new QgsSelectedFeature( m.featureId(), vlayer, mCanvas );
    connect( QgisApp::instance()->layerTreeView(), SIGNAL( currentLayerChanged( QgsMapLayer* ) ), this, SLOT( currentLayerChanged( QgsMapLayer* ) ) );
    connect( mSelectedFeature, SIGNAL( destroyed() ), this, SLOT( selectedFeatureDestroyed() ) );
    connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
    mIsPoint = vlayer->geometryType() == QGis::Point;
  }
예제 #2
0
void QgsMapToolOffsetCurve::canvasMoveEvent( QgsMapMouseEvent* e )
{
  delete mSnapVertexMarker;
  mSnapVertexMarker = nullptr;

  if ( !mOriginalGeometry || !mRubberBand )
  {
    return;
  }

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


  mGeometryModified = true;

  //get offset from current position rectangular to feature
  QgsPoint layerCoords = toLayerCoordinates( layer, e->pos() );

  //snap cursor to background layers
  QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToMap( e->pos() );
  if ( m.isValid() )
  {
    if (( m.layer() && m.layer()->id() != mSourceLayerId ) || m.featureId() != mModifiedFeature )
    {
      layerCoords = toLayerCoordinates( layer, m.point() );
      mSnapVertexMarker = new QgsVertexMarker( mCanvas );
      mSnapVertexMarker->setIconType( QgsVertexMarker::ICON_CROSS );
      mSnapVertexMarker->setColor( Qt::green );
      mSnapVertexMarker->setPenWidth( 1 );
      mSnapVertexMarker->setCenter( m.point() );
    }
  }

  QgsPoint minDistPoint;
  int beforeVertex;
  double leftOf;
  double offset = sqrt( mOriginalGeometry->closestSegmentWithContext( layerCoords, minDistPoint, beforeVertex, &leftOf ) );
  if ( offset == 0.0 )
  {
    return;
  }



  if ( mDistanceWidget )
  {
    // this will also set the rubber band
    mDistanceWidget->setValue( leftOf < 0 ? offset : -offset );
    mDistanceWidget->setFocus( Qt::TabFocusReason );
  }
  else
  {
    //create offset geometry using geos
    setOffsetForRubberBand( leftOf < 0 ? offset : -offset );
  }
}
void QgsMapToolOffsetCurve::canvasPressEvent( QMouseEvent* e )
{
  deleteRubberBandAndGeometry();
  mGeometryModified = false;
  mForceCopy = false;

  if ( !mCanvas )
  {
    return;
  }

  //get selected features or snap to nearest feature if no selection
  QgsVectorLayer* layer = currentVectorLayer();
  if ( !layer )
  {
    notifyNotVectorLayer();
    return;
  }

  QgsSnappingUtils* snapping = mCanvas->snappingUtils();

  // store previous settings
  int oldType;
  double oldSearchRadius;
  QgsTolerance::UnitType oldSearchRadiusUnit;
  QgsSnappingUtils::SnapToMapMode oldMode = snapping->snapToMapMode();
  snapping->defaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );

  // setup new settings (temporary)
  QSettings settings;
  snapping->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
  snapping->setDefaultSettings( QgsPointLocator::Edge,
                                settings.value( "/Qgis/digitizing/search_radius_vertex_edit", 10 ).toDouble(),
                                ( QgsTolerance::UnitType ) settings.value( "/Qgis/digitizing/search_radius_vertex_edit_unit", QgsTolerance::Pixels ).toInt() );

  QgsPointLocator::Match match = snapping->snapToMap( e->pos() );

  // restore old settings
  snapping->setSnapToMapMode( oldMode );
  snapping->setDefaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );

  if ( match.hasEdge() && match.layer() )
  {
    mSourceLayerId = match.layer()->id();
    QgsFeature fet;
    if ( match.layer()->getFeatures( QgsFeatureRequest( match.featureId() ) ).nextFeature( fet ) )
    {
      mForceCopy = ( e->modifiers() & Qt::ControlModifier ); //no geometry modification if ctrl is pressed
      mOriginalGeometry = createOriginGeometry( match.layer(), match, fet );
      mRubberBand = createRubberBand();
      if ( mRubberBand )
      {
        mRubberBand->setToGeometry( mOriginalGeometry, layer );
      }
      mModifiedFeature = fet.id();
      createDistanceItem();
    }
  }
}
예제 #4
0
 void testNearestVertex()
 {
   QgsPointLocator loc( mVL );
   QgsPointXY pt( 2, 2 );
   QgsPointLocator::Match m = loc.nearestVertex( pt, 999 );
   QVERIFY( m.isValid() );
   QVERIFY( m.hasVertex() );
   QCOMPARE( m.layer(), mVL );
   QCOMPARE( m.featureId(), ( QgsFeatureId )1 );
   QCOMPARE( m.point(), QgsPointXY( 1, 1 ) );
   QCOMPARE( m.distance(), std::sqrt( 2.0 ) );
   QCOMPARE( m.vertexIndex(), 2 );
 }
예제 #5
0
    void testPointInPolygon()
    {
      QgsPointLocator loc( mVL );
      QgsPointLocator::MatchList mValid = loc.pointInPolygon( QgsPointXY( 0.8, 0.8 ) );
      QCOMPARE( mValid.count(), 1 );
      QgsPointLocator::Match m = mValid[0];
      QVERIFY( m.isValid() );
      QVERIFY( m.hasArea() );
      QCOMPARE( m.layer(), mVL );
      QCOMPARE( m.featureId(), ( QgsFeatureId )1 );

      QgsPointLocator::MatchList mInvalid = loc.pointInPolygon( QgsPointXY( 0, 0 ) );
      QCOMPARE( mInvalid.count(), 0 );
    }
예제 #6
0
 void testNearestEdge()
 {
   QgsPointLocator loc( mVL );
   QgsPointXY pt( 1.1, 0.5 );
   QgsPointLocator::Match m = loc.nearestEdge( pt, 999 );
   QVERIFY( m.isValid() );
   QVERIFY( m.hasEdge() );
   QCOMPARE( m.layer(), mVL );
   QCOMPARE( m.featureId(), ( QgsFeatureId )1 );
   QCOMPARE( m.point(), QgsPointXY( 1, 0.5 ) );
   QCOMPARE( m.distance(), 0.1 );
   QCOMPARE( m.vertexIndex(), 1 );
   QgsPointXY pt1, pt2;
   m.edgePoints( pt1, pt2 );
   QCOMPARE( pt1, QgsPointXY( 1, 0 ) );
   QCOMPARE( pt2, QgsPointXY( 1, 1 ) );
 }
예제 #7
0
int QgsMapToolCapture::fetchLayerPoint( const QgsPointLocator::Match &match, QgsPoint &layerPoint )
{
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
  QgsVectorLayer *sourceLayer = match.layer();
  if ( match.isValid() && match.hasVertex() && sourceLayer &&
       ( sourceLayer->crs() == vlayer->crs() ) )
  {
    QgsFeature f;
    QgsFeatureRequest request;
    request.setFilterFid( match.featureId() );
    bool fetched = match.layer()->getFeatures( request ).nextFeature( f );
    if ( fetched )
    {
      QgsVertexId vId;
      if ( !f.geometry().vertexIdFromVertexNr( match.vertexIndex(), vId ) )
        return 2;

      layerPoint = f.geometry().constGet()->vertexAt( vId );

      // ZM support depends on the target layer
      if ( !QgsWkbTypes::hasZ( vlayer->wkbType() ) )
      {
        layerPoint.dropZValue();
      }

      if ( !QgsWkbTypes::hasM( vlayer->wkbType() ) )
      {
        layerPoint.dropMValue();
      }

      return 0;
    }
    else
    {
      return 2;
    }
  }
  else
  {
    return 1;
  }
}
예제 #8
0
QgsPoint QgsMapToolCapture::mapPoint( const QgsMapMouseEvent &e ) const
{
  QgsPoint newPoint = mapPoint( e.mapPoint() );

  // set z value from snapped point if necessary
  if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) )
  {
    // if snapped, z dimension is taken from the corresponding snapped
    // point.
    if ( e.isSnapped() )
    {
      const QgsPointLocator::Match match = e.mapPointMatch();

      if ( match.layer() && QgsWkbTypes::hasZ( match.layer()->wkbType() ) )
      {
        const QgsFeature ft = match.layer()->getFeature( match.featureId() );
        newPoint.setZ( ft.geometry().vertexAt( match.vertexIndex() ).z() );
      }
    }
  }

  return newPoint;
}
예제 #9
0
QgsGeometry* QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId& fid, int& partNum )
{
  QgsFeature f;
  QgsGeometry* geomPart = new QgsGeometry();

  switch ( vlayer->geometryType() )
  {
    case QGis::Point:
    case QGis::Line:
    {
      QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Vertex | QgsPointLocator::Edge );
      if ( !match.isValid() )
        return geomPart;

      int snapVertex = match.vertexIndex();
      vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f );
      const QgsGeometry* g = f.constGeometry();
      if ( !g->isMultipart() )
      {
        fid = match.featureId();
        delete geomPart;
        return QgsGeometry::fromPoint( match.point() );
      }
      if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D )
      {
        fid = match.featureId();
        partNum = snapVertex;
        delete geomPart;
        return QgsGeometry::fromPoint( match.point() );
      }
      if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D )
      {
        QgsMultiPolyline mline = g->asMultiPolyline();
        for ( int part = 0; part < mline.count(); part++ )
        {
          if ( snapVertex < mline[part].count() )
          {
            fid = match.featureId();
            partNum = part;
            delete geomPart;
            return QgsGeometry::fromPolyline( mline[part] );
          }
          snapVertex -= mline[part].count();
        }
      }
      break;
    }
    case QGis::Polygon:
    {
      QgsPoint layerCoords = toLayerCoordinates( vlayer, point );
      double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
      QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
                               layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );
      QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) );
      fit.nextFeature( f );
      const QgsGeometry* g = f.constGeometry();
      if ( !g )
        return geomPart;
      if ( !g->isMultipart() )
      {
        fid = f.id();
        return geomPart;
      }
      QgsMultiPolygon mpolygon = g->asMultiPolygon();
      for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons
      {
        const QgsPolygon& polygon = mpolygon[part];
        QgsGeometry* partGeo = QgsGeometry::fromPolygon( polygon );
        if ( partGeo->contains( &layerCoords ) )
        {
          fid = f.id();
          partNum = part;
          delete geomPart;
          return partGeo;
        }
        delete partGeo;
      }
      break;
    }
    default:
    {
      break;
    }
  }
  return geomPart;
}
예제 #10
0
QgsGeometry QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum )
{
  QgsFeature f;
  QgsGeometry geomPart;

  switch ( vlayer->geometryType() )
  {
    case QgsWkbTypes::PointGeometry:
    case QgsWkbTypes::LineGeometry:
    {
      QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) );
      if ( !match.isValid() )
        return geomPart;

      int snapVertex = match.vertexIndex();
      vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f );
      QgsGeometry g = f.geometry();
      if ( !g.isMultipart() )
      {
        fid = match.featureId();
        return QgsGeometry::fromPointXY( match.point() );
      }
      else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::PointGeometry )
      {
        fid = match.featureId();
        partNum = snapVertex;
        return QgsGeometry::fromPointXY( match.point() );
      }
      else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::LineGeometry )
      {
        QgsMultiPolylineXY mline = g.asMultiPolyline();
        for ( int part = 0; part < mline.count(); part++ )
        {
          if ( snapVertex < mline[part].count() )
          {
            fid = match.featureId();
            partNum = part;
            return QgsGeometry::fromPolylineXY( mline[part] );
          }
          snapVertex -= mline[part].count();
        }
      }
      break;
    }
    case QgsWkbTypes::PolygonGeometry:
    {
      QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Area );
      if ( !match.isValid() )
        return geomPart;

      vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f );
      QgsGeometry g = f.geometry();
      if ( g.isNull() )
        return geomPart;

      QgsPointXY layerCoords = toLayerCoordinates( vlayer, point );

      if ( !g.isMultipart() )
      {
        fid = f.id();
        return geomPart;
      }
      QgsMultiPolygonXY mpolygon = g.asMultiPolygon();
      for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons
      {
        const QgsPolygonXY &polygon = mpolygon[part];
        QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon );
        if ( partGeo.contains( &layerCoords ) )
        {
          fid = f.id();
          partNum = part;
          return partGeo;
        }
      }
      break;
    }
    default:
    {
      break;
    }
  }
  return geomPart;
}
예제 #11
0
void QgsMapToolOffsetCurve::canvasReleaseEvent( QgsMapMouseEvent *e )
{
  mCtrlHeldOnFirstClick = false;

  if ( e->button() == Qt::RightButton )
  {
    cancel();
    return;
  }

  if ( mOriginalGeometry.isNull() )
  {
    // first click, get feature to modify
    deleteRubberBandAndGeometry();
    mGeometryModified = false;

    QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(),
                                   QgsPointLocator::Types( QgsPointLocator::Edge | QgsPointLocator::Area ) );

    if ( ( match.hasEdge() || match.hasArea() ) && match.layer() )
    {
      mLayer = match.layer();
      QgsFeature fet;
      if ( match.layer()->getFeatures( QgsFeatureRequest( match.featureId() ) ).nextFeature( fet ) )
      {
        mCtrlHeldOnFirstClick = ( e->modifiers() & Qt::ControlModifier ); //no geometry modification if ctrl is pressed
        prepareGeometry( match, fet );
        mRubberBand = createRubberBand();
        if ( mRubberBand )
        {
          mRubberBand->setToGeometry( mManipulatedGeometry, match.layer() );
        }
        mModifiedFeature = fet.id();
        createUserInputWidget();

        bool hasZ = QgsWkbTypes::hasZ( mLayer->wkbType() );
        bool hasM = QgsWkbTypes::hasZ( mLayer->wkbType() );
        if ( hasZ || hasM )
        {
          emit messageEmitted( QStringLiteral( "layer %1 has %2%3%4 geometry. %2%3%4 values be set to 0 when using offset tool." )
                               .arg( mLayer->name() )
                               .arg( hasZ ? "Z" : "" )
                               .arg( hasZ && hasM ? "/" : "" )
                               .arg( hasM ? "M" : "" )
                               , Qgis::Warning );
        }
      }
    }

    if ( mOriginalGeometry.isNull() )
    {
      emit messageEmitted( tr( "Could not find a nearby feature in any vector layer." ) );
      cancel();
      notifyNotVectorLayer();
    }
  }
  else
  {
    // second click - apply changes
    double offset = calculateOffset( e->snapPoint() );
    applyOffset( offset, e->modifiers() );
  }
}
예제 #12
0
 bool acceptMatch( const QgsPointLocator::Match& match ) override { return match.featureId() == mFid; }