예제 #1
0
    void testLayerUpdates()
    {

      QgsPointLocator loc( mVL );

      QgsPointLocator::Match mAddV0 = loc.nearestVertex( QgsPointXY( 12, 12 ), 999 );
      QVERIFY( mAddV0.isValid() );
      QCOMPARE( mAddV0.point(), QgsPointXY( 1, 1 ) );

      mVL->startEditing();

      // add a new feature
      QgsFeature ff( 0 );
      QgsPolygon polygon;
      QgsPolyline polyline;
      polyline << QgsPointXY( 10, 11 ) << QgsPointXY( 11, 10 ) << QgsPointXY( 11, 11 ) << QgsPointXY( 10, 11 );
      polygon << polyline;
      QgsGeometry ffGeom = QgsGeometry::fromPolygon( polygon ) ;
      ff.setGeometry( ffGeom );
      QgsFeatureList flist;
      flist << ff;
      bool resA = mVL->addFeature( ff );
      QVERIFY( resA );

      // verify it is added in the point locator
      QgsPointLocator::Match mAddV = loc.nearestVertex( QgsPointXY( 12, 12 ), 999 );
      QVERIFY( mAddV.isValid() );
      QCOMPARE( mAddV.point(), QgsPointXY( 11, 11 ) );
      QgsPointLocator::Match mAddE = loc.nearestEdge( QgsPointXY( 11.1, 10.5 ), 999 );
      QVERIFY( mAddE.isValid() );
      QCOMPARE( mAddE.point(), QgsPointXY( 11, 10.5 ) );
      QgsPointLocator::MatchList mAddA = loc.pointInPolygon( QgsPointXY( 10.8, 10.8 ) );
      QVERIFY( mAddA.count() == 1 );

      // change geometry
      QgsGeometry *newGeom = new QgsGeometry( ff.geometry() );
      newGeom->moveVertex( 10, 10, 2 ); // change 11,11 to 10,10
      mVL->changeGeometry( ff.id(), *newGeom );
      delete newGeom;

      // verify it is changed in the point locator
      QgsPointLocator::Match mChV = loc.nearestVertex( QgsPointXY( 12, 12 ), 999 );
      QVERIFY( mChV.isValid() );
      QVERIFY( mChV.point() != QgsPointXY( 11, 11 ) ); // that point does not exist anymore
      mChV = loc.nearestVertex( QgsPointXY( 9, 9 ), 999 );
      QVERIFY( mChV.isValid() );
      QVERIFY( mChV.point() == QgsPointXY( 10, 10 ) ); // updated point

      // delete feature
      bool resD = mVL->deleteFeature( ff.id() );
      QVERIFY( resD );

      // verify it is deleted from the point locator
      QgsPointLocator::Match mDelV = loc.nearestVertex( QgsPointXY( 12, 12 ), 999 );
      QVERIFY( mDelV.isValid() );
      QCOMPARE( mDelV.point(), QgsPointXY( 1, 1 ) );

      mVL->rollBack();
    }
QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers( const QgsPointXY &originalMapPoint, bool *snapped ) const
{
  QList<QgsPointXY> segment;
  QgsPointXY pt1, pt2;
  QgsPointLocator::Match match;

  QgsSnappingUtils *snappingUtils = mMapCanvas->snappingUtils();

  QgsSnappingConfig canvasConfig = snappingUtils->config();
  QgsSnappingConfig localConfig = snappingUtils->config();

  localConfig.setMode( QgsSnappingConfig::AllLayers );
  localConfig.setType( QgsSnappingConfig::Segment );
  snappingUtils->setConfig( localConfig );

  match = snappingUtils->snapToMap( originalMapPoint );

  snappingUtils->setConfig( canvasConfig );

  if ( match.isValid() && match.hasEdge() )
  {
    match.edgePoints( pt1, pt2 );
    segment << pt1 << pt2;
  }

  if ( snapped )
  {
    *snapped = segment.count() == 2;
  }

  return segment;
}
예제 #3
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 );
  }
}
예제 #4
0
void QgsMapCoordsDialog::maybeSetXY( const QgsPoint & xy, Qt::MouseButton button )
{
  // Only LeftButton should set point
  if ( Qt::LeftButton == button )
  {
    QgsPoint mapCoordPoint = xy;
    if ( mQgisCanvas && mSnapToBackgroundLayerBox->isChecked() )
    {
      QgsPointLocator::Match m = mQgisCanvas->snappingUtils()->snapToMap( xy );
      if ( m.isValid() )
        mapCoordPoint = m.point();
    }

    leXCoord->clear();
    leYCoord->clear();
    leXCoord->setText( qgsDoubleToString( mapCoordPoint.x() ) );
    leYCoord->setText( qgsDoubleToString( mapCoordPoint.y() ) );
  }

  parentWidget()->showNormal();
  parentWidget()->activateWindow();
  parentWidget()->raise();

  mPointFromCanvasPushButton->setChecked( false );
  buttonBox->button( QDialogButtonBox::Ok )->setFocus();
  activateWindow();
  raise();
}
예제 #5
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;
  }
예제 #6
0
    void testSnapModeAll()
    {
      QgsMapSettings mapSettings;
      mapSettings.setOutputSize( QSize( 100, 100 ) );
      mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
      QVERIFY( mapSettings.hasValidSettings() );

      QgsSnappingUtils u;
      QgsSnappingConfig snappingConfig = u.config();
      u.setMapSettings( mapSettings );
      snappingConfig.setMode( QgsSnappingConfig::AllLayers );
      u.setConfig( snappingConfig );

      // right now there are no layers in map settings - snapping will fail

      QgsPointLocator::Match m = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( !m.isValid() );

      // now check with our layer
      mapSettings.setLayers( QStringList() << mVL->id() );
      u.setMapSettings( mapSettings );

      QgsPointLocator::Match m2 = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( m2.isValid() );
      QCOMPARE( m2.point(), QgsPoint( 1, 0 ) );
    }
예제 #7
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 );
 }
예제 #8
0
    void testSnapOnIntersection()
    {
      // testing with a layer with two crossing linestrings
      // (0,1)  x  x (1,1)
      //         \/
      //         /\    .
      // (0,0)  x  x (1,0)
      QgsVectorLayer* vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
      QgsPolyline polyline1, polyline2;
      polyline1 << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 );
      polyline2 << QgsPoint( 1, 0 ) << QgsPoint( 0, 1 );
      QgsFeature f1;
      QgsGeometry f1g = QgsGeometry::fromPolyline( polyline1 ) ;
      f1.setGeometry( f1g );
      QgsFeature f2;
      QgsGeometry f2g = QgsGeometry::fromPolyline( polyline2 );
      f2.setGeometry( f2g );
      QgsFeatureList flist;
      flist << f1 << f2;
      vl->dataProvider()->addFeatures( flist );

      QVERIFY( vl->dataProvider()->featureCount() == 2 );

      QgsMapSettings mapSettings;
      mapSettings.setOutputSize( QSize( 100, 100 ) );
      mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
      QVERIFY( mapSettings.hasValidSettings() );

      QgsSnappingUtils u;
      u.setMapSettings( mapSettings );
      QgsSnappingConfig snappingConfig = u.config();
      snappingConfig.setMode( QgsSnappingConfig::AdvancedConfiguration );
      QgsSnappingConfig::IndividualLayerSettings layerSettings( true, QgsSnappingConfig::Vertex, 0.1, QgsTolerance::ProjectUnits );
      snappingConfig.setIndividualLayerSettings( vl, layerSettings );
      u.setConfig( snappingConfig );

      // no snapping on intersections by default - should find nothing
      QgsPointLocator::Match m = u.snapToMap( QgsPoint( 0.45, 0.5 ) );
      QVERIFY( !m.isValid() );

      snappingConfig.setIntersectionSnapping( true );
      u.setConfig( snappingConfig );

      QgsPointLocator::Match m2 = u.snapToMap( QgsPoint( 0.45, 0.5 ) );
      QVERIFY( m2.isValid() );
      QCOMPARE( m2.type(), QgsPointLocator::Vertex );
      QCOMPARE( m2.point(), QgsPoint( 0.5, 0.5 ) );

      delete vl;
    }
예제 #9
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 );
    }
예제 #10
0
QList<QgsPoint> QgsMapMouseEvent::snapSegment( SnappingMode snappingMode, bool* snapped , bool allLayers ) const
{
  QList<QgsPoint> segment;
  QgsPoint pt1, pt2;

  // If there's a cached snapping result we use it
  if ( snappingMode == mSnappingMode && mSnapMatch.hasEdge() )
  {
    mSnapMatch.edgePoints( pt1, pt2 );
    segment << pt1 << pt2;
  }

  else if ( snappingMode != NoSnapping )
  {
    QgsPointLocator::Match match;
    if ( snappingMode == SnapProjectConfig && !allLayers )
    {
      // run snapToMap with only segments
      EdgesOnlyFilter filter;
      match = mMapCanvas->snappingUtils()->snapToMap( mOriginalMapPoint, &filter );
    }
    else if ( snappingMode == SnapAllLayers || allLayers )
    {
      // run snapToMap with only edges on all layers
      QgsSnappingUtils* snappingUtils = mMapCanvas->snappingUtils();
      QgsSnappingUtils::SnapToMapMode canvasMode = snappingUtils->snapToMapMode();
      int type;
      double tolerance;
      QgsTolerance::UnitType unit;
      snappingUtils->defaultSettings( type, tolerance, unit );
      snappingUtils->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
      snappingUtils->setDefaultSettings( QgsPointLocator::Edge, tolerance, unit );
      match = snappingUtils->snapToMap( mOriginalMapPoint );
      snappingUtils->setSnapToMapMode( canvasMode );
      snappingUtils->setDefaultSettings( type, tolerance, unit );
    }
    if ( match.isValid() && match.hasEdge() )
    {
      match.edgePoints( pt1, pt2 );
      segment << pt1 << pt2;
    }
  }

  if ( snapped )
  {
    *snapped = segment.count() == 2;
  }

  return segment;
}
예제 #11
0
    void testSnapModeCurrent()
    {
      QgsMapSettings mapSettings;
      mapSettings.setOutputSize( QSize( 100, 100 ) );
      mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
      QVERIFY( mapSettings.hasValidSettings() );

      QgsSnappingUtils u;
      u.setMapSettings( mapSettings );
      u.setCurrentLayer( mVL );

      // first try with no snapping enabled
      QgsSnappingConfig snappingConfig = u.config();
      snappingConfig.setEnabled( false );
      snappingConfig.setTolerance( 10 );
      snappingConfig.setUnits( QgsTolerance::Pixels );
      snappingConfig.setMode( QgsSnappingConfig::ActiveLayer );
      u.setConfig( snappingConfig );

      QgsPointLocator::Match m0 = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( !m0.isValid() );
      QVERIFY( !m0.hasVertex() );

      // now enable snapping
      snappingConfig.setEnabled( true );
      snappingConfig.setType( QgsSnappingConfig::Vertex );
      u.setConfig( snappingConfig );

      QgsPointLocator::Match m = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( m.isValid() );
      QVERIFY( m.hasVertex() );
      QCOMPARE( m.point(), QgsPoint( 1, 0 ) );

      QgsPointLocator::Match m2 = u.snapToMap( QPoint( 0, 100 ) );
      QVERIFY( !m2.isValid() );
      QVERIFY( !m2.hasVertex() );

      // do not consider edges in the following test - on 32-bit platforms
      // result was an edge match very close to (1,0) instead of being exactly (1,0)

      snappingConfig.setType( QgsSnappingConfig::Vertex );
      u.setConfig( snappingConfig );

      // test with filtering
      FilterExcludePoint myFilter( QgsPoint( 1, 0 ) );
      QgsPointLocator::Match m3 = u.snapToMap( QPoint( 100, 100 ), &myFilter );
      QVERIFY( !m3.isValid() );
    }
예제 #12
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 ) );
 }
예제 #13
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;
  }
}
예제 #14
0
    void testSnapModeAdvanced()
    {
      QgsMapSettings mapSettings;
      mapSettings.setOutputSize( QSize( 100, 100 ) );
      mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
      QVERIFY( mapSettings.hasValidSettings() );

      QgsSnappingUtils u;
      QgsSnappingConfig snappingConfig = u.config();
      u.setMapSettings( mapSettings );
      snappingConfig.setMode( QgsSnappingConfig::AdvancedConfiguration );
      snappingConfig.setIndividualLayerSettings( mVL, QgsSnappingConfig::IndividualLayerSettings( true, QgsSnappingConfig::Vertex, 10, QgsTolerance::Pixels ) );
      u.setConfig( snappingConfig );

      QgsPointLocator::Match m = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( m.isValid() );
      QVERIFY( m.hasVertex() );
      QCOMPARE( m.point(), QgsPoint( 1, 0 ) );

      // test with filtering
      FilterExcludePoint myFilter( QgsPoint( 1, 0 ) );
      QgsPointLocator::Match m2 = u.snapToMap( QPoint( 100, 100 ), &myFilter );
      QVERIFY( !m2.isValid() );
    }
예제 #15
0
    void testSnapModeAdvanced()
    {
      QgsMapSettings mapSettings;
      mapSettings.setOutputSize( QSize( 100, 100 ) );
      mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
      QVERIFY( mapSettings.hasValidSettings() );

      QgsSnappingUtils u;
      u.setMapSettings( mapSettings );
      u.setSnapToMapMode( QgsSnappingUtils::SnapAdvanced );
      QList<QgsSnappingUtils::LayerConfig> layers;
      layers << QgsSnappingUtils::LayerConfig( mVL, QgsPointLocator::Vertex, 10, QgsTolerance::Pixels );
      u.setLayers( layers );

      QgsPointLocator::Match m = u.snapToMap( QPoint( 100, 100 ) );
      QVERIFY( m.isValid() );
      QVERIFY( m.hasVertex() );
      QCOMPARE( m.point(), QgsPoint( 1, 0 ) );

      // test with filtering
      FilterExcludePoint myFilter( QgsPoint( 1, 0 ) );
      QgsPointLocator::Match m2 = u.snapToMap( QPoint( 100, 100 ), &myFilter );
      QVERIFY( !m2.isValid() );
    }
예제 #16
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;
}
예제 #17
0
파일: qgscadutils.cpp 프로젝트: GeoCat/QGIS
QgsCadUtils::AlignMapPointOutput QgsCadUtils::alignMapPoint( const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx )
{
  QgsCadUtils::AlignMapPointOutput res;
  res.valid = true;
  res.softLockCommonAngle = -1;

  // try to snap to anything
  QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint );
  QgsPointXY point = snapMatch.isValid() ? snapMatch.point() : originalMapPoint;

  // try to snap explicitly to a segment - useful for some constraints
  QgsPointXY edgePt0, edgePt1;
  EdgesOnlyFilter edgesOnlyFilter;
  QgsPointLocator::Match edgeMatch = ctx.snappingUtils->snapToMap( originalMapPoint, &edgesOnlyFilter );
  if ( edgeMatch.hasEdge() )
    edgeMatch.edgePoints( edgePt0, edgePt1 );

  res.edgeMatch = edgeMatch;

  QgsPointXY previousPt, penultimatePt;
  if ( ctx.cadPointList.count() >= 2 )
    previousPt = ctx.cadPointList.at( 1 );
  if ( ctx.cadPointList.count() >= 3 )
    penultimatePt = ctx.cadPointList.at( 2 );

  // *****************************
  // ---- X constraint
  if ( ctx.xConstraint.locked )
  {
    if ( !ctx.xConstraint.relative )
    {
      point.setX( ctx.xConstraint.value );
    }
    else if ( ctx.cadPointList.count() >= 2 )
    {
      point.setX( previousPt.x() + ctx.xConstraint.value );
    }
    if ( edgeMatch.hasEdge() && !ctx.yConstraint.locked )
    {
      // intersect with snapped segment line at X ccordinate
      const double dx = edgePt1.x() - edgePt0.x();
      if ( dx == 0 )
      {
        point.setY( edgePt0.y() );
      }
      else
      {
        const double dy = edgePt1.y() - edgePt0.y();
        point.setY( edgePt0.y() + ( dy * ( point.x() - edgePt0.x() ) ) / dx );
      }
    }
  }

  // *****************************
  // ---- Y constraint
  if ( ctx.yConstraint.locked )
  {
    if ( !ctx.yConstraint.relative )
    {
      point.setY( ctx.yConstraint.value );
    }
    else if ( ctx.cadPointList.count() >= 2 )
    {
      point.setY( previousPt.y() + ctx.yConstraint.value );
    }
    if ( edgeMatch.hasEdge() && !ctx.xConstraint.locked )
    {
      // intersect with snapped segment line at Y ccordinate
      const double dy = edgePt1.y() - edgePt0.y();
      if ( dy == 0 )
      {
        point.setX( edgePt0.x() );
      }
      else
      {
        const double dx = edgePt1.x() - edgePt0.x();
        point.setX( edgePt0.x() + ( dx * ( point.y() - edgePt0.y() ) ) / dy );
      }
    }
  }

  // *****************************
  // ---- Common Angle constraint
  if ( !ctx.angleConstraint.locked && ctx.cadPointList.count() >= 2 && ctx.commonAngleConstraint.locked && ctx.commonAngleConstraint.value != 0 )
  {
    double commonAngle = ctx.commonAngleConstraint.value * M_PI / 180;
    // see if soft common angle constraint should be performed
    // only if not in HardLock mode
    double softAngle = std::atan2( point.y() - previousPt.y(),
                                   point.x() - previousPt.x() );
    double deltaAngle = 0;
    if ( ctx.commonAngleConstraint.relative && ctx.cadPointList.count() >= 3 )
    {
      // compute the angle relative to the last segment (0° is aligned with last segment)
      deltaAngle = std::atan2( previousPt.y() - penultimatePt.y(),
                               previousPt.x() - penultimatePt.x() );
      softAngle -= deltaAngle;
    }
    int quo = std::round( softAngle / commonAngle );
    if ( std::fabs( softAngle - quo * commonAngle ) * 180.0 * M_1_PI <= SOFT_CONSTRAINT_TOLERANCE_DEGREES )
    {
      // also check the distance in pixel to the line, otherwise it's too sticky at long ranges
      softAngle = quo * commonAngle;
      // http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
      // use the direction vector (cos(a),sin(a)) from previous point. |x2-x1|=1 since sin2+cos2=1
      const double dist = std::fabs( std::cos( softAngle + deltaAngle ) * ( previousPt.y() - point.y() )
                                     - std::sin( softAngle + deltaAngle ) * ( previousPt.x() - point.x() ) );
      if ( dist / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
      {
        res.softLockCommonAngle = 180.0 / M_PI * softAngle;
      }
    }
  }

  // angle can be locked in one of the two ways:
  // 1. "hard" lock defined by the user
  // 2. "soft" lock from common angle (e.g. 45 degrees)
  bool angleLocked = false, angleRelative = false;
  int angleValueDeg = 0;
  if ( ctx.angleConstraint.locked )
  {
    angleLocked = true;
    angleRelative = ctx.angleConstraint.relative;
    angleValueDeg = ctx.angleConstraint.value;
  }
  else if ( res.softLockCommonAngle != -1 )
  {
    angleLocked = true;
    angleRelative = ctx.commonAngleConstraint.relative;
    angleValueDeg = res.softLockCommonAngle;
  }

  // *****************************
  // ---- Angle constraint
  // input angles are in degrees
  if ( angleLocked )
  {
    double angleValue = angleValueDeg * M_PI / 180;
    if ( angleRelative && ctx.cadPointList.count() >= 3 )
    {
      // compute the angle relative to the last segment (0° is aligned with last segment)
      angleValue += std::atan2( previousPt.y() - penultimatePt.y(),
                                previousPt.x() - penultimatePt.x() );
    }

    double cosa = std::cos( angleValue );
    double sina = std::sin( angleValue );
    double v = ( point.x() - previousPt.x() ) * cosa + ( point.y() - previousPt.y() ) * sina;
    if ( ctx.xConstraint.locked && ctx.yConstraint.locked )
    {
      // do nothing if both X,Y are already locked
    }
    else if ( ctx.xConstraint.locked )
    {
      if ( qgsDoubleNear( cosa, 0.0 ) )
      {
        res.valid = false;
      }
      else
      {
        double x = ctx.xConstraint.value;
        if ( !ctx.xConstraint.relative )
        {
          x -= previousPt.x();
        }
        point.setY( previousPt.y() + x * sina / cosa );
      }
    }
    else if ( ctx.yConstraint.locked )
    {
      if ( qgsDoubleNear( sina, 0.0 ) )
      {
        res.valid = false;
      }
      else
      {
        double y = ctx.yConstraint.value;
        if ( !ctx.yConstraint.relative )
        {
          y -= previousPt.y();
        }
        point.setX( previousPt.x() + y * cosa / sina );
      }
    }
    else
    {
      point.setX( previousPt.x() + cosa * v );
      point.setY( previousPt.y() + sina * v );
    }

    if ( edgeMatch.hasEdge() && !ctx.distanceConstraint.locked )
    {
      // magnetize to the intersection of the snapped segment and the lockedAngle

      // line of previous point + locked angle
      const double x1 = previousPt.x();
      const double y1 = previousPt.y();
      const double x2 = previousPt.x() + cosa;
      const double y2 = previousPt.y() + sina;
      // line of snapped segment
      const double x3 = edgePt0.x();
      const double y3 = edgePt0.y();
      const double x4 = edgePt1.x();
      const double y4 = edgePt1.y();

      const double d = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );

      // do not compute intersection if lines are almost parallel
      // this threshold might be adapted
      if ( std::fabs( d ) > 0.01 )
      {
        point.setX( ( ( x3 - x4 ) * ( x1 * y2 - y1 * x2 ) - ( x1 - x2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
        point.setY( ( ( y3 - y4 ) * ( x1 * y2 - y1 * x2 ) - ( y1 - y2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
      }
    }
  }

  // *****************************
  // ---- Distance constraint
  if ( ctx.distanceConstraint.locked && ctx.cadPointList.count() >= 2 )
  {
    if ( ctx.xConstraint.locked || ctx.yConstraint.locked )
    {
      // perform both to detect errors in constraints
      if ( ctx.xConstraint.locked )
      {
        QgsPointXY verticalPt0( ctx.xConstraint.value, point.y() );
        QgsPointXY verticalPt1( ctx.xConstraint.value, point.y() + 1 );
        res.valid &= lineCircleIntersection( previousPt, ctx.distanceConstraint.value, verticalPt0, verticalPt1, point );
      }
      if ( ctx.yConstraint.locked )
      {
        QgsPointXY horizontalPt0( point.x(), ctx.yConstraint.value );
        QgsPointXY horizontalPt1( point.x() + 1, ctx.yConstraint.value );
        res.valid &= lineCircleIntersection( previousPt, ctx.distanceConstraint.value, horizontalPt0, horizontalPt1, point );
      }
    }
    else
    {
      const double dist = std::sqrt( point.sqrDist( previousPt ) );
      if ( dist == 0 )
      {
        // handle case where mouse is over origin and distance constraint is enabled
        // take arbitrary horizontal line
        point.set( previousPt.x() + ctx.distanceConstraint.value, previousPt.y() );
      }
      else
      {
        const double vP = ctx.distanceConstraint.value / dist;
        point.set( previousPt.x() + ( point.x() - previousPt.x() ) * vP,
                   previousPt.y() + ( point.y() - previousPt.y() ) * vP );
      }

      if ( edgeMatch.hasEdge() && !ctx.angleConstraint.locked )
      {
        // we will magnietize to the intersection of that segment and the lockedDistance !
        res.valid &= lineCircleIntersection( previousPt, ctx.distanceConstraint.value, edgePt0, edgePt1, point );
      }
    }
  }

  // *****************************
  // ---- calculate CAD values
  QgsDebugMsgLevel( QString( "point:             %1 %2" ).arg( point.x() ).arg( point.y() ), 4 );
  QgsDebugMsgLevel( QString( "previous point:    %1 %2" ).arg( previousPt.x() ).arg( previousPt.y() ), 4 );
  QgsDebugMsgLevel( QString( "penultimate point: %1 %2" ).arg( penultimatePt.x() ).arg( penultimatePt.y() ), 4 );
  //QgsDebugMsg( QString( "dx: %1 dy: %2" ).arg( point.x() - previousPt.x() ).arg( point.y() - previousPt.y() ) );
  //QgsDebugMsg( QString( "ddx: %1 ddy: %2" ).arg( previousPt.x() - penultimatePt.x() ).arg( previousPt.y() - penultimatePt.y() ) );

  res.finalMapPoint = point;

  return res;
}
예제 #18
0
QgsPoint QgsMapToolMeasureAngle::snapPoint( const QPoint& p )
{
  QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToMap( p );
  return m.isValid() ? m.point() : mCanvas->getCoordinateTransform()->toMapCoordinates( p );
}
예제 #19
0
void QgsMapToolSplitFeatures::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  bool split = false;


  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    //If we snap the first point on a vertex of a line layer, we directly split the feature at this point
    if ( vlayer->geometryType() == QgsWkbTypes::LineGeometry && points().isEmpty() )
    {
      QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex );
      if ( m.isValid() )
      {
        split = true;
      }
    }

    int error = addVertex( e->mapPoint(), e->mapPointMatch() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "Coordinate transform error" ),
        tr( "Cannot transform the point to the layers coordinate system" ),
        QgsMessageBar::INFO,
        QgisApp::instance()->messageTimeout() );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    split = true;
  }

  if ( split )
  {
    deleteTempRubberBand();

    //bring up dialog if a split was not possible (polygon) or only done once (line)
    int topologicalEditing = QgsProject::instance()->topologicalEditing();
    vlayer->beginEditCommand( tr( "Features split" ) );
    int returnCode = vlayer->splitFeatures( points(), topologicalEditing );
    vlayer->endEditCommand();
    if ( returnCode == 4 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No features were split" ),
        tr( "If there are selected features, the split tool only applies to those. If you would like to split all features under the split line, clear the selection." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode == 3 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "Cut edges detected. Make sure the line splits features into multiple parts." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode == 7 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "The geometry is invalid. Please repair before trying to split it." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode != 0 )
    {
      //several intersections but only one split (most likely line)
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "An error occurred during splitting." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }

    stopCapturing();
  }
}
예제 #20
0
void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
{
  if ( !mSelectedFeature || !mClicked )
    return;

  QgsVectorLayer* vlayer = mSelectedFeature->vlayer();
  Q_ASSERT( vlayer );

  mSelectAnother = false;

  if ( mMoving )
  {
    // create rubberband, if none exists
    if ( mRubberBands.empty() )
    {
      if ( mIsPoint )
      {
        QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
        for ( int i = 0; i < vertexMap.size(); i++ )
        {
          if ( vertexMap[i]->isSelected() )
          {
            QgsRubberBand* rb = createRubberBandMarker( vertexMap[i]->point(), vlayer );
            mRubberBands.append( rb );
          }
        }
      }
      createMovingRubberBands();

      mPosMapCoordBackup = toMapCoordinates( e->pos() );
    }
    else
    {
      // move rubberband
      QgsPoint posMapCoord, pressMapCoords;
      QgsExcludePointFilter excludePointFilter( mClosestMapVertex );
      QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( e->pos(), &excludePointFilter );
      if ( match.isValid() )
      {
        posMapCoord = match.point();
        pressMapCoords = mClosestMapVertex;
      }
      else
      {
        posMapCoord = toMapCoordinates( e->pos() );
        pressMapCoords = toMapCoordinates( mPressCoordinates );
      }

      QgsVector offset = posMapCoord - pressMapCoords;

      // handle points
      if ( mIsPoint )
      {
        for ( int i = 0; i < mRubberBands.size(); i++ )
        {
          mRubberBands[i]->setTranslationOffset( offset.x(), offset.y() );
        }
        return;
      }

      // move points
      QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
      for ( int i = 0; i < vertexMap.size(); i++ )
      {
        if ( !vertexMap[i]->isSelected() )
          continue;

        QgsPoint p = toMapCoordinates( vlayer, vertexMap[i]->point() ) + offset;

        mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), p );

        if ( vertexMap[i]->rubberBandIndex() == 0 )
        {
          mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, p );
        }
      }

      // topological editing
      offset = posMapCoord - mPosMapCoordBackup;
      for ( int i = 0; i < mTopologyRubberBand.size(); i++ )
      {
        for ( int pointIndex = 0; pointIndex < mTopologyRubberBand[i]->numberOfVertices(); pointIndex++ )
        {
          if ( mTopologyRubberBandVertexes[i]->contains( pointIndex ) )
          {
            const QgsPoint* point = mTopologyRubberBand[i]->getPoint( 0, pointIndex );
            if ( point == 0 )
            {
              break;
            }
            mTopologyRubberBand[i]->movePoint( pointIndex, *point + offset );
          }
        }
      }

      mPosMapCoordBackup = posMapCoord;
    }
  }
  else
  {
    if ( !mSelectionRectangle )
    {
      mSelectionRectangle = true;
      mSelectionRubberBand = new QRubberBand( QRubberBand::Rectangle, mCanvas );
      mRect = new QRect();
      mRect->setTopLeft( mPressCoordinates );
    }
    mRect->setBottomRight( e->pos() );
    QRect normalizedRect = mRect->normalized();
    mSelectionRubberBand->setGeometry( normalizedRect );
    mSelectionRubberBand->show();
  }
}
void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
{
  if ( !mAdvancedDigitizingDockWidget->cadEnabled() )
    return;

  QgsRectangle mapRect = mMapCanvas->extent();
  if ( rect() != mapRect )
    setRect( mapRect );

  int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
  if ( !nPoints )
    return;

  bool previousPointExist, penulPointExist;
  const QgsPointXY curPoint = mAdvancedDigitizingDockWidget->currentPoint();
  const QgsPointXY prevPoint = mAdvancedDigitizingDockWidget->previousPoint( &previousPointExist );
  const QgsPointXY penulPoint = mAdvancedDigitizingDockWidget->penultimatePoint( &penulPointExist );
  const bool snappedToVertex = mAdvancedDigitizingDockWidget->snappedToVertex();
  const QList<QgsPointXY> snappedSegment = mAdvancedDigitizingDockWidget->snappedSegment();
  const bool hasSnappedSegment = snappedSegment.count() == 2;

  const bool curPointExist = mapRect.contains( curPoint );

  const double mupp = mMapCanvas->getCoordinateTransform()->mapUnitsPerPixel();
  if ( mupp == 0 )
    return;

  QPointF curPointPix, prevPointPix, penulPointPix, snapSegmentPix1, snapSegmentPix2;

  if ( curPointExist )
  {
    curPointPix = toCanvasCoordinates( curPoint );
  }
  if ( previousPointExist )
  {
    prevPointPix = toCanvasCoordinates( prevPoint );
  }
  if ( penulPointExist )
  {
    penulPointPix = toCanvasCoordinates( penulPoint );
  }
  if ( hasSnappedSegment )
  {
    snapSegmentPix1 = toCanvasCoordinates( snappedSegment[0] );
    snapSegmentPix2 = toCanvasCoordinates( snappedSegment[1] );
  }

  painter->setRenderHint( QPainter::Antialiasing );
  painter->setCompositionMode( QPainter::CompositionMode_Difference );

  // Draw point snap
  if ( curPointExist && snappedToVertex )
  {
    painter->setPen( mSnapPen );
    painter->drawEllipse( curPointPix, 10, 10 );
  }

  // Draw segment snap
  if ( hasSnappedSegment && !snappedToVertex )
  {
    painter->setPen( mSnapPen );
    painter->drawLine( snapSegmentPix1, snapSegmentPix2 );

    if ( curPointExist )
    {
      painter->setPen( mSnapLinePen );
      painter->drawLine( snapSegmentPix1, curPointPix );
    }
  }

  // Draw segment par/per input
  if ( mAdvancedDigitizingDockWidget->additionalConstraint() != QgsAdvancedDigitizingDockWidget::NoConstraint && hasSnappedSegment )
  {
    painter->setPen( mConstruction2Pen );
    painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
  }

  // Draw angle
  if ( nPoints > 1 )
  {
    double a0, a;
    if ( mAdvancedDigitizingDockWidget->constraintAngle()->relative() && nPoints > 2 )
    {
      a0 = std::atan2( -( prevPoint.y() - penulPoint.y() ), prevPoint.x() - penulPoint.x() );
    }
    else
    {
      a0 = 0;
    }
    if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
    {
      a = a0 - mAdvancedDigitizingDockWidget->constraintAngle()->value() * M_PI / 180;
    }
    else
    {
      a = std::atan2( -( curPoint.y() - prevPoint.y() ), curPoint.x() - prevPoint.x() );
    }
    painter->setPen( mConstruction2Pen );
    painter->drawArc( QRectF( prevPointPix.x() - 20,
                              prevPointPix.y() - 20,
                              40, 40 ),
                      static_cast<int>( 16 * -a0 * 180 / M_PI ),
                      static_cast<int>( 16 * ( a0 - a ) * 180 / M_PI ) );
    painter->drawLine( prevPointPix,
                       prevPointPix + 60 * QPointF( std::cos( a0 ), std::sin( a0 ) ) );


    if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
    {
      painter->setPen( mLockedPen );
      double d = std::max( boundingRect().width(), boundingRect().height() );
      painter->drawLine( prevPointPix - d * QPointF( std::cos( a ), std::sin( a ) ),
                         prevPointPix + d * QPointF( std::cos( a ), std::sin( a ) ) );
    }
  }

  // Draw distance
  if ( nPoints > 1 && mAdvancedDigitizingDockWidget->constraintDistance()->isLocked() )
  {
    painter->setPen( mLockedPen );
    double r = mAdvancedDigitizingDockWidget->constraintDistance()->value() / mupp;
    painter->drawEllipse( prevPointPix, r, r );
  }

  // Draw x
  if ( mAdvancedDigitizingDockWidget->constraintX()->isLocked() )
  {
    double x = 0.0;
    bool draw = true;
    painter->setPen( mLockedPen );
    if ( mAdvancedDigitizingDockWidget->constraintX()->relative() )
    {
      if ( nPoints > 1 )
      {
        x = mAdvancedDigitizingDockWidget->constraintX()->value() / mupp + prevPointPix.x();
      }
      else
      {
        draw = false;
      }
    }
    else
    {
      x = toCanvasCoordinates( QgsPointXY( mAdvancedDigitizingDockWidget->constraintX()->value(), 0 ) ).x();
    }
    if ( draw )
    {
      painter->drawLine( QPointF( x, 0 ),
                         QPointF( x, boundingRect().height() ) );
    }
  }

  // Draw y
  if ( mAdvancedDigitizingDockWidget->constraintY()->isLocked() )
  {
    double y = 0.0;
    bool draw = true;
    painter->setPen( mLockedPen );
    if ( mAdvancedDigitizingDockWidget->constraintY()->relative() )
    {
      if ( nPoints > 1 )
      {
        // y is reversed!
        y = -mAdvancedDigitizingDockWidget->constraintY()->value() / mupp + prevPointPix.y();
      }
      else
      {
        draw = false;
      }
    }
    else
    {
      y = toCanvasCoordinates( QgsPointXY( 0, mAdvancedDigitizingDockWidget->constraintY()->value() ) ).y();
    }
    if ( draw )
    {
      painter->drawLine( QPointF( 0, y ),
                         QPointF( boundingRect().width(), y ) );
    }
  }

  // Draw constr
  if ( mAdvancedDigitizingDockWidget->additionalConstraint() == QgsAdvancedDigitizingDockWidget::NoConstraint )
  {
    if ( curPointExist && previousPointExist )
    {
      painter->setPen( mConstruction2Pen );
      painter->drawLine( prevPointPix, curPointPix );
    }

    if ( previousPointExist && penulPointExist )
    {
      painter->setPen( mConstruction1Pen );
      painter->drawLine( penulPointPix, prevPointPix );
    }
  }

  if ( curPointExist )
  {
    painter->setPen( mCursorPen );
    painter->drawLine( curPointPix + QPointF( -5, -5 ),
                       curPointPix + QPointF( +5, +5 ) );
    painter->drawLine( curPointPix + QPointF( -5, +5 ),
                       curPointPix + QPointF( +5, -5 ) );
  }


  QgsPointLocator::Match match = mAdvancedDigitizingDockWidget->mapPointMatch();
  if ( match.isValid() )
  {
    mSnapIndicator->setMatch( match );
    mSnapIndicator->setVisible( true );
  }
  else
    mSnapIndicator->setVisible( false );

}
예제 #22
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;
}