diff --git a/images/images.qrc b/images/images.qrc index 8eabb4d080d5..510392d92898 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -508,6 +508,8 @@ themes/default/mIconClear.png flags/zh.png themes/default/mIconPaintEffects.svg + themes/default/mActionCircularStringCurvePoint.png + themes/default/mActionCircularStringRadius.png qgis_tips/symbol_levels.png diff --git a/images/themes/default/mActionCircularStringCurvePoint.png b/images/themes/default/mActionCircularStringCurvePoint.png new file mode 100644 index 000000000000..19b3445210ca Binary files /dev/null and b/images/themes/default/mActionCircularStringCurvePoint.png differ diff --git a/images/themes/default/mActionCircularStringRadius.png b/images/themes/default/mActionCircularStringRadius.png new file mode 100644 index 000000000000..2a1e5d1bcda9 Binary files /dev/null and b/images/themes/default/mActionCircularStringRadius.png differ diff --git a/python/core/geometry/qgsabstractgeometryv2.sip b/python/core/geometry/qgsabstractgeometryv2.sip index 54289f297f6f..2439150fa56c 100644 --- a/python/core/geometry/qgsabstractgeometryv2.sip +++ b/python/core/geometry/qgsabstractgeometryv2.sip @@ -90,7 +90,7 @@ class QgsAbstractGeometryV2 virtual QgsRectangle calculateBoundingBox() const; //render pipeline - virtual void transform( const QgsCoordinateTransform& ct ) = 0; + virtual void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) = 0; virtual void transform( const QTransform& t ) = 0; //virtual void clip( const QgsRectangle& rect ); virtual void draw( QPainter& p ) const = 0; diff --git a/python/core/geometry/qgscircularstringv2.sip b/python/core/geometry/qgscircularstringv2.sip index 48d312dd5511..322d8d2c0e7a 100644 --- a/python/core/geometry/qgscircularstringv2.sip +++ b/python/core/geometry/qgscircularstringv2.sip @@ -38,7 +38,7 @@ class QgsCircularStringV2: public QgsCurveV2 virtual QgsLineStringV2* curveToLine() const; void draw( QPainter& p ) const; - void transform( const QgsCoordinateTransform& ct ); + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); //void clip( const QgsRectangle& rect ); void addToPainterPath( QPainterPath& path ) const; diff --git a/python/core/geometry/qgscompoundcurvev2.sip b/python/core/geometry/qgscompoundcurvev2.sip index 558a7cd86343..ed69bcd6bcdf 100644 --- a/python/core/geometry/qgscompoundcurvev2.sip +++ b/python/core/geometry/qgscompoundcurvev2.sip @@ -45,7 +45,7 @@ class QgsCompoundCurveV2: public QgsCurveV2 void close(); void draw( QPainter& p ) const; - void transform( const QgsCoordinateTransform& ct ); + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); void addToPainterPath( QPainterPath& path ) const; void drawAsPolygon( QPainter& p ) const; diff --git a/python/core/geometry/qgscurvepolygonv2.sip b/python/core/geometry/qgscurvepolygonv2.sip index 8616636efbc0..24db6e286859 100644 --- a/python/core/geometry/qgscurvepolygonv2.sip +++ b/python/core/geometry/qgscurvepolygonv2.sip @@ -49,7 +49,7 @@ class QgsCurvePolygonV2: public QgsSurfaceV2 bool removeInteriorRing( int nr ); virtual void draw( QPainter& p ) const; - void transform( const QgsCoordinateTransform& ct ); + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); virtual bool insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ); diff --git a/python/core/geometry/qgsgeometrycollectionv2.sip b/python/core/geometry/qgsgeometrycollectionv2.sip index 3819ebe63194..5ea302a62b4a 100644 --- a/python/core/geometry/qgsgeometrycollectionv2.sip +++ b/python/core/geometry/qgsgeometrycollectionv2.sip @@ -23,7 +23,7 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2 virtual bool addGeometry( QgsAbstractGeometryV2* g /Transfer/ ); virtual bool removeGeometry( int nr ); - virtual void transform( const QgsCoordinateTransform& ct ); + virtual void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); //virtual void clip( const QgsRectangle& rect ); virtual void draw( QPainter& p ) const; diff --git a/python/core/geometry/qgslinestringv2.sip b/python/core/geometry/qgslinestringv2.sip index 938306952720..93a2eadea62a 100644 --- a/python/core/geometry/qgslinestringv2.sip +++ b/python/core/geometry/qgslinestringv2.sip @@ -38,7 +38,7 @@ class QgsLineStringV2: public QgsCurveV2 void append( const QgsLineStringV2* line ); void draw( QPainter& p ) const; - void transform( const QgsCoordinateTransform& ct ); + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); void addToPainterPath( QPainterPath& path ) const; diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 0af5453e3fd1..7ab5ee17d6a7 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -119,6 +119,9 @@ SET(QGIS_APP_SRCS qgsvectorlayerproperties.cpp qgsvisibilitypresets.cpp qgshandlebadlayers.cpp + qgsmaptooladdcircularstring.cpp + qgsmaptoolcircularstringcurvepoint.cpp + qgsmaptoolcircularstringradius.cpp composer/qgsattributeselectiondialog.cpp composer/qgscomposer.cpp @@ -217,6 +220,7 @@ SET (QGIS_APP_MOC_HDRS qgsmaptooladdfeature.h qgsmaptoolcapture.h + qgsmaptoolcircularstringradius.h qgsmaptooladdpart.h qgsmaptooladdring.h qgsmaptooledit.h @@ -245,6 +249,7 @@ SET (QGIS_APP_MOC_HDRS qgsmaptoolsimplify.h qgsmaptoolsplitfeatures.h qgsmaptoolsplitparts.h + qgsmaptooladdcircularstring.h nodetool/qgsmaptoolnodetool.h nodetool/qgsselectedfeature.h diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 233fbf435f83..f823c8f8c414 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -253,6 +253,8 @@ #include "qgsmaptooladdring.h" #include "qgsmaptoolfillring.h" #include "qgsmaptoolannotation.h" +#include "qgsmaptoolcircularstringcurvepoint.h" +#include "qgsmaptoolcircularstringradius.h" #include "qgsmaptooldeletering.h" #include "qgsmaptooldeletepart.h" #include "qgsmaptoolfeatureaction.h" @@ -288,7 +290,6 @@ // Editor widgets #include "qgseditorwidgetregistry.h" - // // Conditional Includes // @@ -1206,6 +1207,8 @@ void QgisApp::createActions() connect( mActionCopyStyle, SIGNAL( triggered() ), this, SLOT( copyStyle() ) ); connect( mActionPasteStyle, SIGNAL( triggered() ), this, SLOT( pasteStyle() ) ); connect( mActionAddFeature, SIGNAL( triggered() ), this, SLOT( addFeature() ) ); + connect( mActionCircularStringCurvePoint, SIGNAL( triggered() ), this, SLOT( circularStringCurvePoint() ) ); + connect( mActionCircularStringRadius, SIGNAL( triggered() ), this, SLOT( circularStringRadius() ) ); connect( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) ); connect( mActionRotateFeature, SIGNAL( triggered() ), this, SLOT( rotateFeature() ) ); @@ -1480,6 +1483,8 @@ void QgisApp::createActionGroups() mMapToolGroup->addAction( mActionMeasureArea ); mMapToolGroup->addAction( mActionMeasureAngle ); mMapToolGroup->addAction( mActionAddFeature ); + mMapToolGroup->addAction( mActionCircularStringCurvePoint ); + mMapToolGroup->addAction( mActionCircularStringRadius ); mMapToolGroup->addAction( mActionMoveFeature ); mMapToolGroup->addAction( mActionRotateFeature ); #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ @@ -2329,6 +2334,10 @@ void QgisApp::createCanvasTools() mMapTools.mAnnotation->setAction( mActionAnnotation ); mMapTools.mAddFeature = new QgsMapToolAddFeature( mMapCanvas ); mMapTools.mAddFeature->setAction( mActionAddFeature ); + mMapTools.mCircularStringCurvePoint = new QgsMapToolCircularStringCurvePoint( dynamic_cast( mMapTools.mAddFeature ), mMapCanvas ); + mMapTools.mCircularStringCurvePoint->setAction( mActionCircularStringCurvePoint ); + mMapTools.mCircularStringRadius = new QgsMapToolCircularStringRadius( dynamic_cast( mMapTools.mAddFeature ), mMapCanvas ); + mMapTools.mCircularStringRadius->setAction( mActionCircularStringRadius ); mMapTools.mMoveFeature = new QgsMapToolMoveFeature( mMapCanvas ); mMapTools.mMoveFeature->setAction( mActionMoveFeature ); mMapTools.mRotateFeature = new QgsMapToolRotateFeature( mMapCanvas ); @@ -6233,6 +6242,16 @@ void QgisApp::addFeature() mMapCanvas->setMapTool( mMapTools.mAddFeature ); } +void QgisApp::circularStringCurvePoint() +{ + mMapCanvas->setMapTool( mMapTools.mCircularStringCurvePoint ); +} + +void QgisApp::circularStringRadius() +{ + mMapCanvas->setMapTool( mMapTools.mCircularStringRadius ); +} + void QgisApp::selectFeatures() { mMapCanvas->setMapTool( mMapTools.mSelectFeatures ); diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 3a10030c88ff..43b031e02f8a 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -971,6 +971,10 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow void newBookmark(); //! activates the add feature tool void addFeature(); + //! activates the add circular string tool + void circularStringCurvePoint(); + //! activates the circular string radius tool + void circularStringRadius(); //! activates the move feature tool void moveFeature(); //! activates the offset curve tool @@ -1481,6 +1485,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QgsMapTool *mMeasureArea; QgsMapTool *mMeasureAngle; QgsMapTool *mAddFeature; + QgsMapTool *mCircularStringCurvePoint; + QgsMapTool *mCircularStringRadius; QgsMapTool *mMoveFeature; QgsMapTool *mOffsetCurve; QgsMapTool *mReshapeFeatures; diff --git a/src/app/qgsmaptooladdcircularstring.cpp b/src/app/qgsmaptooladdcircularstring.cpp new file mode 100644 index 000000000000..607dc7b0b8e6 --- /dev/null +++ b/src/app/qgsmaptooladdcircularstring.cpp @@ -0,0 +1,182 @@ +/*************************************************************************** + qgsmaptooladdcircularstring.h - map tool for adding circular strings + --------------------- + begin : December 2014 + copyright : (C) 2014 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmaptooladdcircularstring.h" +#include "qgscircularstringv2.h" +#include "qgscompoundcurvev2.h" +#include "qgscurvepolygonv2.h" +#include "qgsgeometryrubberband.h" +#include "qgsgeometryutils.h" +#include "qgslinestringv2.h" +#include "qgsmapcanvas.h" +#include "qgspointv2.h" +#include + +QgsMapToolAddCircularString::QgsMapToolAddCircularString( QgsMapToolCapture* parentTool, QgsMapCanvas* canvas, CaptureMode mode ): QgsMapToolCapture( canvas, mode ), + mParentTool( parentTool ), mRubberBand( 0 ), mShowCenterPointRubberBand( false ), mCenterPointRubberBand( 0 ) +{ + if ( mCanvas ) + { + connect( mCanvas, SIGNAL( mapToolSet( QgsMapTool*, QgsMapTool* ) ), this, SLOT( setParentTool( QgsMapTool*, QgsMapTool* ) ) ); + } +} + +QgsMapToolAddCircularString::QgsMapToolAddCircularString( QgsMapCanvas* canvas ): QgsMapToolCapture( canvas ), mParentTool( 0 ), + mRubberBand( 0 ), mShowCenterPointRubberBand( false ), mCenterPointRubberBand( 0 ) +{ + if ( mCanvas ) + { + connect( mCanvas, SIGNAL( mapToolSet( QgsMapTool*, QgsMapTool* ) ), this, SLOT( setParentTool( QgsMapTool*, QgsMapTool* ) ) ); + } +} + +QgsMapToolAddCircularString::~QgsMapToolAddCircularString() +{ + delete mRubberBand; + removeCenterPointRubberBand(); +} + +void QgsMapToolAddCircularString::setParentTool( QgsMapTool* newTool, QgsMapTool* oldTool ) +{ + QgsMapToolCapture* tool = dynamic_cast( oldTool ); + QgsMapToolAddCircularString* csTool = dynamic_cast( oldTool ); + if ( csTool && newTool == this ) + { + mParentTool = csTool->mParentTool; + } + else if ( tool && newTool == this ) + { + mParentTool = tool; + } +} + +void QgsMapToolAddCircularString::keyPressEvent( QKeyEvent* e ) +{ + if ( e->isAutoRepeat() ) + { + return; + } + + if ( e && e->key() == Qt::Key_R ) + { + mShowCenterPointRubberBand = true; + + createCenterPointRubberBand(); + } +} + +void QgsMapToolAddCircularString::keyReleaseEvent( QKeyEvent* e ) +{ + if ( e->isAutoRepeat() ) + { + return; + } + + if ( e && e->key() == Qt::Key_R ) + { + removeCenterPointRubberBand(); + mShowCenterPointRubberBand = false; + } +} + +void QgsMapToolAddCircularString::deactivate() +{ + if ( !mParentTool || mPoints.size() < 3 ) + { + return; + } + + if ( mPoints.size() % 2 == 0 ) //a valid circularstring needs to have an odd number of vertices + { + mPoints.removeLast(); + } + + QgsCircularStringV2* c = new QgsCircularStringV2(); + c->setPoints( mPoints ); + mParentTool->addCurve( c ); + mPoints.clear(); + delete mRubberBand; mRubberBand = 0; + removeCenterPointRubberBand(); +} + +void QgsMapToolAddCircularString::createCenterPointRubberBand() +{ + if ( !mShowCenterPointRubberBand || mPoints.size() < 2 || mPoints.size() % 2 != 0 ) + { + return; + } + + mCenterPointRubberBand = createGeometryRubberBand( QGis::Polygon ); + mCenterPointRubberBand->show(); + + if ( mRubberBand ) + { + const QgsAbstractGeometryV2* rubberBandGeom = mRubberBand->geometry(); + if ( rubberBandGeom ) + { + QgsVertexId idx; idx.part = 0; idx.ring = 0; idx.vertex = mPoints.size(); + QgsPointV2 pt = rubberBandGeom->vertexAt( idx ); + updateCenterPointRubberBand( pt ); + } + } +} + +void QgsMapToolAddCircularString::updateCenterPointRubberBand( const QgsPointV2& pt ) +{ + if ( !mShowCenterPointRubberBand || !mCenterPointRubberBand || mPoints.size() < 2 ) + { + return; + } + + if (( mPoints.size() ) % 2 != 0 ) + { + return; + } + + //create circular string + QgsCircularStringV2* cs = new QgsCircularStringV2(); + QList< QgsPointV2 > csPoints; + csPoints.append( mPoints.at( mPoints.size() - 2 ) ); + csPoints.append( mPoints.at( mPoints.size() - 1 ) ); + csPoints.append( pt ); + cs->setPoints( csPoints ); + + double centerX, centerY; + double radius; + QgsGeometryUtils::circleCenterRadius( csPoints.at( 0 ), csPoints.at( 1 ), csPoints.at( 2 ), radius, centerX, centerY ); + + QgsLineStringV2* segment1 = new QgsLineStringV2(); + segment1->addVertex( QgsPointV2( centerX, centerY ) ); + segment1->addVertex( csPoints.at( 0 ) ); + + QgsLineStringV2* segment2 = new QgsLineStringV2(); + segment2->addVertex( csPoints.at( 2 ) ); + segment2->addVertex( QgsPointV2( centerX, centerY ) ); + + QgsCompoundCurveV2* cc = new QgsCompoundCurveV2(); + cc->addCurve( segment1 ); + cc->addCurve( cs ); + cc->addCurve( segment2 ); + + QgsCurvePolygonV2* cp = new QgsCurvePolygonV2(); + cp->setExteriorRing( cc ); + mCenterPointRubberBand->setGeometry( cp ); + mCenterPointRubberBand->show(); +} + +void QgsMapToolAddCircularString::removeCenterPointRubberBand() +{ + delete mCenterPointRubberBand; mCenterPointRubberBand = 0; +} diff --git a/src/app/qgsmaptooladdcircularstring.h b/src/app/qgsmaptooladdcircularstring.h new file mode 100644 index 000000000000..112b49285583 --- /dev/null +++ b/src/app/qgsmaptooladdcircularstring.h @@ -0,0 +1,55 @@ +/*************************************************************************** + qgsmaptooladdcircularstring.h - map tool for adding circular strings + --------------------- + begin : December 2014 + copyright : (C) 2014 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLADDCIRCULARSTRING_H +#define QGSMAPTOOLADDCIRCULARSTRING_H + +#include "qgsmaptoolcapture.h" + +class QgsGeometryRubberBand; + +class QgsMapToolAddCircularString: public QgsMapToolCapture +{ + Q_OBJECT + public: + QgsMapToolAddCircularString( QgsMapToolCapture* parentTool, QgsMapCanvas* canvas, CaptureMode mode = CaptureLine ); + ~QgsMapToolAddCircularString(); + + void keyPressEvent( QKeyEvent* e ); + void keyReleaseEvent( QKeyEvent* e ); + + void deactivate(); + + private slots: + void setParentTool( QgsMapTool* newTool, QgsMapTool* oldTool ); + + protected: + QgsMapToolAddCircularString( QgsMapCanvas* canvas = 0 ); //forbidden + + QgsMapToolCapture* mParentTool; + /** Circular string points (in map coordinates)*/ + QList< QgsPointV2 > mPoints; + QgsGeometryRubberBand* mRubberBand; + + //center point rubber band + bool mShowCenterPointRubberBand; + QgsGeometryRubberBand* mCenterPointRubberBand; + + void createCenterPointRubberBand(); + void updateCenterPointRubberBand( const QgsPointV2& pt ); + void removeCenterPointRubberBand(); +}; + +#endif // QGSMAPTOOLADDCIRCULARSTRING_H diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 33edfc6b5003..52f7adcbfeef 100644 --- a/src/app/qgsmaptooladdfeature.cpp +++ b/src/app/qgsmaptooladdfeature.cpp @@ -17,11 +17,14 @@ #include "qgsapplication.h" #include "qgsattributedialog.h" #include "qgscsexception.h" +#include "qgscurvepolygonv2.h" #include "qgsfield.h" #include "qgsgeometry.h" +#include "qgslinestringv2.h" #include "qgsmapcanvas.h" #include "qgsmaplayerregistry.h" #include "qgsmapmouseevent.h" +#include "qgspolygonv2.h" #include "qgsproject.h" #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" @@ -199,56 +202,46 @@ void QgsMapToolAddFeature::canvasMapReleaseEvent( QgsMapMouseEvent* e ) return; } + if ( mode() == CapturePolygon ) + { + closePolygon(); + } + //create QgsFeature with wkb representation QgsFeature* f = new QgsFeature( vlayer->fields(), 0 ); - QgsGeometry *g; + //does compoundcurve contain circular strings? + //does provider support circular strings? + bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); + bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; - if ( mode() == CaptureLine ) + QgsCurveV2* curveToAdd = 0; + if ( hasCurvedSegments && providerSupportsCurvedSegments ) { - if ( layerWKBType == QGis::WKBLineString || layerWKBType == QGis::WKBLineString25D ) - { - g = QgsGeometry::fromPolyline( points().toVector() ); - } - else if ( layerWKBType == QGis::WKBMultiLineString || layerWKBType == QGis::WKBMultiLineString25D ) - { - g = QgsGeometry::fromMultiPolyline( QgsMultiPolyline() << points().toVector() ); - } - else - { - emit messageEmitted( tr( "Cannot add feature. Unknown WKB type" ), QgsMessageBar::CRITICAL ); - stopCapturing(); - delete f; - return; //unknown wkbtype - } + curveToAdd = dynamic_cast( captureCurve()->clone() ); + } + else + { + curveToAdd = captureCurve()->curveToLine(); + } - f->setGeometry( g ); + if ( mode() == CaptureLine ) + { + f->setGeometry( new QgsGeometry( curveToAdd ) ); } - else // polygon + else { - if ( layerWKBType == QGis::WKBPolygon || layerWKBType == QGis::WKBPolygon25D ) + QgsCurvePolygonV2* poly = 0; + if ( hasCurvedSegments && providerSupportsCurvedSegments ) { - g = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() ); - } - else if ( layerWKBType == QGis::WKBMultiPolygon || layerWKBType == QGis::WKBMultiPolygon25D ) - { - g = QgsGeometry::fromMultiPolygon( QgsMultiPolygon() << ( QgsPolygon() << points().toVector() ) ); + poly = new QgsCurvePolygonV2(); } else { - emit messageEmitted( tr( "Cannot add feature. Unknown WKB type" ), QgsMessageBar::CRITICAL ); - stopCapturing(); - delete f; - return; //unknown wkbtype - } - - if ( !g ) - { - stopCapturing(); - delete f; - return; // invalid geometry; one possibility is from duplicate points + poly = new QgsPolygonV2(); } - f->setGeometry( g ); + poly->setExteriorRing( curveToAdd ); + f->setGeometry( poly ); int avoidIntersectionsReturn = f->geometry()->avoidIntersections(); if ( avoidIntersectionsReturn == 1 ) diff --git a/src/app/qgsmaptooladdpart.cpp b/src/app/qgsmaptooladdpart.cpp index d0f9110d2fb3..c45d91809482 100644 --- a/src/app/qgsmaptooladdpart.cpp +++ b/src/app/qgsmaptooladdpart.cpp @@ -14,9 +14,12 @@ ***************************************************************************/ #include "qgsmaptooladdpart.h" +#include "qgscurvepolygonv2.h" #include "qgsgeometry.h" +#include "qgslinestringv2.h" #include "qgsmapcanvas.h" #include "qgsproject.h" +#include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" #include "qgslogger.h" @@ -67,7 +70,7 @@ void QgsMapToolAddPart::canvasMapReleaseEvent( QgsMapMouseEvent * e ) return; } - int errorCode; + int errorCode = 0; switch ( mode() ) { case CapturePoint: @@ -118,33 +121,51 @@ void QgsMapToolAddPart::canvasMapReleaseEvent( QgsMapMouseEvent * e ) if ( !isCapturing() ) return; - // we are now going to finish the capturing - if ( mode() == CapturePolygon ) { - //close polygon closePolygon(); + } + + //does compoundcurve contain circular strings? + //does provider support circular strings? + bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); + bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; + + QgsCurveV2* curveToAdd = 0; + if ( hasCurvedSegments && providerSupportsCurvedSegments ) + { + curveToAdd = dynamic_cast( captureCurve()->clone() ); + } + else + { + curveToAdd = captureCurve()->curveToLine(); + } + + vlayer->beginEditCommand( tr( "Part added" ) ); + if ( mode() == CapturePolygon ) + { //avoid intersections - QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() ); - if ( geom ) + QgsCurvePolygonV2* cp = new QgsCurvePolygonV2(); + cp->setExteriorRing( curveToAdd ); + QgsGeometry* geom = new QgsGeometry( cp ); + geom->avoidIntersections(); + + const QgsCurvePolygonV2* cpGeom = dynamic_cast( geom->geometry() ); + if ( !cpGeom ) { - geom->avoidIntersections(); - QgsPolygon poly = geom->asPolygon(); - if ( poly.size() < 1 ) - { - stopCapturing(); - delete geom; - vlayer->destroyEditCommand(); - return; - } - setPoints( geom->asPolygon()[0].toList() ); + stopCapturing(); delete geom; + vlayer->destroyEditCommand(); + return; } - } - - vlayer->beginEditCommand( tr( "Part added" ) ); - errorCode = vlayer->addPart( points() ); + errorCode = vlayer->addPart( dynamic_cast( cpGeom->exteriorRing()->clone() ) ); + delete geom; + } + else + { + errorCode = vlayer->addPart( curveToAdd ); + } stopCapturing(); } break; diff --git a/src/app/qgsmaptooladdring.cpp b/src/app/qgsmaptooladdring.cpp index 15b0b84cb82b..57ac4a2088ec 100644 --- a/src/app/qgsmaptooladdring.cpp +++ b/src/app/qgsmaptooladdring.cpp @@ -17,8 +17,10 @@ #include "qgsmaptooladdring.h" #include "qgsgeometry.h" +#include "qgslinestringv2.h" #include "qgsmapcanvas.h" #include "qgsproject.h" +#include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" @@ -80,7 +82,23 @@ void QgsMapToolAddRing::canvasMapReleaseEvent( QgsMapMouseEvent * e ) closePolygon(); vlayer->beginEditCommand( tr( "Ring added" ) ); - int addRingReturnCode = vlayer->addRing( points() ); + + //does compoundcurve contain circular strings? + //does provider support circular strings? + bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); + bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; + + QgsCurveV2* curveToAdd = 0; + if ( hasCurvedSegments && providerSupportsCurvedSegments ) + { + curveToAdd = dynamic_cast( captureCurve()->clone() ); + } + else + { + curveToAdd = captureCurve()->curveToLine(); + } + + int addRingReturnCode = vlayer->addRing( curveToAdd ); if ( addRingReturnCode != 0 ) { QString errorMessage; diff --git a/src/app/qgsmaptoolcapture.cpp b/src/app/qgsmaptoolcapture.cpp index 9fb23b5b72bb..0a4248fbe0cd 100644 --- a/src/app/qgsmaptoolcapture.cpp +++ b/src/app/qgsmaptoolcapture.cpp @@ -19,10 +19,12 @@ #include "qgscursors.h" #include "qgsgeometryvalidator.h" #include "qgslayertreeview.h" +#include "qgslinestringv2.h" #include "qgslogger.h" #include "qgsmapcanvas.h" #include "qgsmapmouseevent.h" #include "qgsmaprenderer.h" +#include "qgspolygonv2.h" #include "qgsrubberband.h" #include "qgsvectorlayer.h" #include "qgsvertexmarker.h" @@ -167,6 +169,13 @@ int QgsMapToolCapture::nextPoint( const QgsPoint& mapPoint, QgsPoint& layerPoint return 0; } +int QgsMapToolCapture::nextPoint( const QPoint &p, QgsPoint &layerPoint, QgsPoint &mapPoint ) +{ + + mapPoint = toMapCoordinates( p ); + return nextPoint( mapPoint, layerPoint ); +} + int QgsMapToolCapture::addVertex( const QgsPoint& point ) { if ( mode() == CaptureNone ) @@ -188,7 +197,7 @@ int QgsMapToolCapture::addVertex( const QgsPoint& point ) mRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QGis::Polygon : QGis::Line ); } mRubberBand->addPoint( point ); - mCaptureList.append( layerPoint ); + mCaptureCurve.addVertex( QgsPointV2( layerPoint.x(), layerPoint.y() ) ); if ( !mTempRubberBand ) { @@ -215,6 +224,51 @@ int QgsMapToolCapture::addVertex( const QgsPoint& point ) return 0; } +int QgsMapToolCapture::addCurve( QgsCurveV2* c ) +{ + if ( !c ) + { + return 1; + } + + if ( !mRubberBand ) + { + mRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QGis::Polygon : QGis::Line ); + } + + QgsLineStringV2* lineString = c->curveToLine(); + QList linePoints; + lineString->points( linePoints ); + delete lineString; + QList::const_iterator ptIt = linePoints.constBegin(); + for ( ; ptIt != linePoints.constEnd(); ++ptIt ) + { + mRubberBand->addPoint( QgsPoint( ptIt->x(), ptIt->y() ) ); + } + + if ( !mTempRubberBand ) + { + mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QGis::Polygon : QGis::Line, true ); + } + else + { + mTempRubberBand->reset(); + } + QgsPointV2 endPt = c->endPoint(); + mTempRubberBand->addPoint( QgsPoint( endPt.x(), endPt.y() ) ); //add last point of c + + //transform back to layer CRS in case map CRS and layer CRS are different + QgsVectorLayer* vlayer = qobject_cast( mCanvas->currentLayer() ); + const QgsCoordinateTransform* ct = mCanvas->mapSettings().layerTransform( vlayer ); + if ( ct ) + { + c->transform( *ct, QgsCoordinateTransform::ReverseTransform ); + } + mCaptureCurve.addCurve( c ); + + return 0; +} + void QgsMapToolCapture::undo() { @@ -222,7 +276,7 @@ void QgsMapToolCapture::undo() { int rubberBandSize = mRubberBand->numberOfVertices(); int tempRubberBandSize = mTempRubberBand->numberOfVertices(); - int captureListSize = mCaptureList.size(); + int captureListSize = size(); if ( rubberBandSize < 1 || captureListSize < 1 ) { @@ -244,7 +298,9 @@ void QgsMapToolCapture::undo() mTempRubberBand->reset( mCaptureMode == CapturePolygon ? true : false ); } - mCaptureList.removeLast(); + QgsVertexId vertexToRemove; + vertexToRemove.part = 0; vertexToRemove.ring = 0; vertexToRemove.vertex = size() - 1; + mCaptureCurve.deleteVertex( vertexToRemove ); validateGeometry(); } @@ -298,7 +354,7 @@ void QgsMapToolCapture::stopCapturing() #endif mCapturing = false; - mCaptureList.clear(); + mCaptureCurve.clear(); mCanvas->refresh(); } @@ -313,7 +369,7 @@ void QgsMapToolCapture::deleteTempRubberBand() void QgsMapToolCapture::closePolygon() { - mCaptureList.append( mCaptureList[0] ); + mCaptureCurve.close(); } void QgsMapToolCapture::validateGeometry() @@ -343,14 +399,18 @@ void QgsMapToolCapture::validateGeometry() case CapturePoint: return; case CaptureLine: - if ( mCaptureList.size() < 2 ) + if ( size() < 2 ) return; - g = QgsGeometry::fromPolyline( mCaptureList.toVector() ); + g = new QgsGeometry( mCaptureCurve.curveToLine() ); break; case CapturePolygon: - if ( mCaptureList.size() < 3 ) + if ( size() < 3 ) return; - g = QgsGeometry::fromPolygon( QgsPolygon() << ( QgsPolyline() << mCaptureList.toVector() << mCaptureList[0] ) ); + QgsLineStringV2* exteriorRing = mCaptureCurve.curveToLine(); + exteriorRing->close(); + QgsPolygonV2* polygon = new QgsPolygonV2(); + polygon->setExteriorRing( exteriorRing ); + g = new QgsGeometry( polygon ); break; } @@ -402,3 +462,29 @@ void QgsMapToolCapture::validationFinished() QStatusBar *sb = QgisApp::instance()->statusBar(); sb->showMessage( tr( "Validation finished." ) ); } + +int QgsMapToolCapture::size() +{ + return mCaptureCurve.numPoints(); +} + +QList QgsMapToolCapture::points() +{ + QList pts; + QList points; + mCaptureCurve.points( pts ); + QgsGeometry::convertPointList( pts, points ); + return points; +} + +void QgsMapToolCapture::setPoints( const QList& pointList ) +{ + QList pts; + QgsGeometry::convertPointList( pointList, pts ); + + QgsLineStringV2* line = new QgsLineStringV2(); + line->setPoints( pts ); + + mCaptureCurve.clear(); + mCaptureCurve.addCurve( line ); +} diff --git a/src/app/qgsmaptoolcapture.h b/src/app/qgsmaptoolcapture.h index 6d85979c7c8d..739b485c15a5 100644 --- a/src/app/qgsmaptoolcapture.h +++ b/src/app/qgsmaptoolcapture.h @@ -18,6 +18,7 @@ #include "qgsmaptooledit.h" +#include "qgscompoundcurvev2.h" #include "qgspoint.h" #include "qgsgeometry.h" @@ -52,6 +53,11 @@ class APP_EXPORT QgsMapToolCapture : public QgsMapToolEdit //! deactive the tool virtual void deactivate() override; + /** Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be in map CRS*/ + int addCurve( QgsCurveV2* c ); + + const QgsCompoundCurveV2* captureCurve() const { return &mCaptureCurve; } + public slots: void currentLayerChanged( QgsMapLayer *layer ); void addError( QgsGeometry::Error ); @@ -59,6 +65,7 @@ class APP_EXPORT QgsMapToolCapture : public QgsMapToolEdit protected: int nextPoint( const QgsPoint& mapPoint, QgsPoint& layerPoint ); + int nextPoint( const QPoint &p, QgsPoint &layerPoint, QgsPoint &mapPoint ); /** Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates) @return 0 in case of success, 1 if current layer is not a vector layer, 2 if coordinate transformation failed*/ @@ -72,11 +79,9 @@ class APP_EXPORT QgsMapToolCapture : public QgsMapToolEdit void stopCapturing(); void deleteTempRubberBand(); - int size() { return mCaptureList.size(); } - QList::iterator begin() { return mCaptureList.begin(); } - QList::iterator end() { return mCaptureList.end(); } - const QList &points() { return mCaptureList; } - void setPoints( const QList& pointList ) { mCaptureList = pointList; } + int size(); + QList points(); + void setPoints( const QList& pointList ); void closePolygon(); private: @@ -90,7 +95,7 @@ class APP_EXPORT QgsMapToolCapture : public QgsMapToolEdit QgsRubberBand* mTempRubberBand; /** List to store the points of digitised lines and polygons (in layer coordinates)*/ - QList mCaptureList; + QgsCompoundCurveV2 mCaptureCurve; void validateGeometry(); QString mTip; diff --git a/src/app/qgsmaptoolcircularstringcurvepoint.cpp b/src/app/qgsmaptoolcircularstringcurvepoint.cpp new file mode 100644 index 000000000000..43d451c756b0 --- /dev/null +++ b/src/app/qgsmaptoolcircularstringcurvepoint.cpp @@ -0,0 +1,87 @@ +#include "qgsmaptoolcircularstringcurvepoint.h" +#include "qgscircularstringv2.h" +#include "qgscompoundcurvev2.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspointv2.h" +#include + +QgsMapToolCircularStringCurvePoint::QgsMapToolCircularStringCurvePoint( QgsMapToolCapture* parentTool, + QgsMapCanvas* canvas, CaptureMode mode ): QgsMapToolAddCircularString( parentTool, canvas, mode ) +{ + +} + +QgsMapToolCircularStringCurvePoint::~QgsMapToolCircularStringCurvePoint() +{ +} + +void QgsMapToolCircularStringCurvePoint::canvasMapReleaseEvent( QgsMapMouseEvent* e ) +{ + QgsPointV2 mapPoint( e->mapPoint().x(), e->mapPoint().y() ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.size() < 1 ) //connection to vertex of previous line segment needed? + { + const QgsCompoundCurveV2* compoundCurve = mParentTool->captureCurve(); + if ( compoundCurve ) + { + if ( compoundCurve->nCurves() > 0 ) + { + const QgsCurveV2* curve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 ); + if ( curve ) + { + //mParentTool->captureCurve() is in layer coordinates, but we need map coordinates + QgsPointV2 endPointLayerCoord = curve->endPoint(); + QgsPoint mapPoint = toMapCoordinates( mCanvas->currentLayer(), QgsPoint( endPointLayerCoord.x(), endPointLayerCoord.y() ) ); + mPoints.append( QgsPointV2( mapPoint.x(), mapPoint.y() ) ); + } + } + } + } + mPoints.append( mapPoint ); + if ( !mCenterPointRubberBand && mShowCenterPointRubberBand ) + { + createCenterPointRubberBand(); + } + + if ( mPoints.size() > 1 ) + { + if ( !mRubberBand ) + { + mRubberBand = createGeometryRubberBand(( mCaptureMode == CapturePolygon ) ? QGis::Polygon : QGis::Line ); + mRubberBand->show(); + } + + QgsCircularStringV2* c = new QgsCircularStringV2(); + QList< QgsPointV2 > rubberBandPoints = mPoints; + rubberBandPoints.append( mapPoint ); + c->setPoints( rubberBandPoints ); + mRubberBand->setGeometry( c ); + } + if (( mPoints.size() ) % 2 == 1 ) + { + removeCenterPointRubberBand(); + } + } + else if ( e->button() == Qt::RightButton ) + { + deactivate(); + if ( mParentTool ) + { + mParentTool->canvasReleaseEvent( e ); + } + } +} + +void QgsMapToolCircularStringCurvePoint::canvasMapMoveEvent( QgsMapMouseEvent* e ) +{ + QgsPointV2 mapPoint( e->mapPoint().x(), e->mapPoint().y() ); + QgsVertexId idx; idx.part = 0; idx.ring = 0; idx.vertex = mPoints.size(); + if ( mRubberBand ) + { + mRubberBand->moveVertex( idx, mapPoint ); + updateCenterPointRubberBand( mapPoint ); + } +} diff --git a/src/app/qgsmaptoolcircularstringcurvepoint.h b/src/app/qgsmaptoolcircularstringcurvepoint.h new file mode 100644 index 000000000000..d0d03ed28d82 --- /dev/null +++ b/src/app/qgsmaptoolcircularstringcurvepoint.h @@ -0,0 +1,32 @@ +/*************************************************************************** + qgsmaptoolcircularstringcurvepoint.h - map tool for adding circular + strings by start / curve / endpoint + --------------------- + begin : Feb 2015 + copyright : (C) 2015 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H +#define QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H + +#include "qgsmaptooladdcircularstring.h" + +class QgsMapToolCircularStringCurvePoint: public QgsMapToolAddCircularString +{ + public: + QgsMapToolCircularStringCurvePoint( QgsMapToolCapture* parentTool, QgsMapCanvas* canvas, CaptureMode mode = CaptureLine ); + ~QgsMapToolCircularStringCurvePoint(); + + void canvasMapReleaseEvent( QgsMapMouseEvent* e ) override; + void canvasMapMoveEvent( QgsMapMouseEvent* e ) override; +}; + +#endif // QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H diff --git a/src/app/qgsmaptoolcircularstringradius.cpp b/src/app/qgsmaptoolcircularstringradius.cpp new file mode 100644 index 000000000000..85a83b48d8f5 --- /dev/null +++ b/src/app/qgsmaptoolcircularstringradius.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + qgsmaptoolcircularstringradius.h - map tool for adding circular strings + --------------------- + begin : Feb 2015 + copyright : (C) 2015 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmaptoolcircularstringradius.h" +#include "qgisapp.h" +#include "qgscircularstringv2.h" +#include "qgscompoundcurvev2.h" +#include "qgsgeometryutils.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspointv2.h" +#include +#include +#include + +QgsMapToolCircularStringRadius::QgsMapToolCircularStringRadius( QgsMapToolCapture* parentTool, QgsMapCanvas* canvas, CaptureMode mode ) : + QgsMapToolAddCircularString( parentTool, canvas, mode ), mTemporaryEndPointX( 0.0 ), mTemporaryEndPointY( 0.0 ), mRadiusMode( false ), mRadius( 0.0 ), + mRadiusSpinBox( 0 ) +{ + +} + +QgsMapToolCircularStringRadius::~QgsMapToolCircularStringRadius() +{ + +} + +void QgsMapToolCircularStringRadius::canvasMapReleaseEvent( QgsMapMouseEvent* e ) +{ + QgsPointV2 mapPoint( e->mapPoint().x(), e->mapPoint().y() ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.size() == 0 ) + { + //get first point from parent tool if there. Todo: move to upper class + const QgsCompoundCurveV2* compoundCurve = mParentTool->captureCurve(); + if ( compoundCurve && compoundCurve->nCurves() > 0 ) + { + const QgsCurveV2* curve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 ); + if ( curve ) + { + //mParentTool->captureCurve() is in layer coordinates, but we need map coordinates + QgsPointV2 endPointLayerCoord = curve->endPoint(); + QgsPoint mapPoint = toMapCoordinates( mCanvas->currentLayer(), QgsPoint( endPointLayerCoord.x(), endPointLayerCoord.y() ) ); + mPoints.append( QgsPointV2( mapPoint.x(), mapPoint.y() ) ); + } + } + else + { + mPoints.append( mapPoint ); + return; + } + } + + if ( mPoints.size() % 2 == 1 ) + { + if ( !mRadiusMode ) + { + delete mRubberBand; mRubberBand = 0; + mTemporaryEndPointX = mapPoint.x(); + mTemporaryEndPointY = mapPoint.y(); + mRadiusMode = true; + + //initial radius is distance( tempPoint - mPoints.last ) / 2.0 + double minRadius = sqrt( QgsGeometryUtils::sqrDistance2D( mPoints.last(), QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ) ) ) / 2.0; + mRadius = minRadius + minRadius / 10.0; + recalculateCircularString(); + createRadiusSpinBox(); + if ( mRadiusSpinBox ) + { + mRadiusSpinBox->setMinimum( minRadius ); + } + } + else + { + QgsPointV2 result; + if ( QgsGeometryUtils::segmentMidPoint( mPoints.last(), QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ), result, mRadius, QgsPointV2( mapPoint.x(), mapPoint.y() ) ) ) + { + mPoints.append( result ); + mPoints.append( QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ) ); + } + mRadiusMode = false; + deleteRadiusSpinBox(); + } + } + else + { + //can we get there? + } + } + else if ( e->button() == Qt::RightButton ) + { + deactivate(); + if ( mParentTool ) + { + mParentTool->canvasReleaseEvent( e ); + } + } +} + +void QgsMapToolCircularStringRadius::canvasMapMoveEvent( QgsMapMouseEvent* e ) +{ + if ( mPoints.size() > 0 && mRadiusMode ) + { + mLastMouseMapPos.setX( e->mapPoint().x() ); + mLastMouseMapPos.setY( e->mapPoint().y() ); + recalculateCircularString(); + } +} + +void QgsMapToolCircularStringRadius::recalculateCircularString() +{ + //new midpoint on circle segment + QgsPointV2 midPoint; + if ( !QgsGeometryUtils::segmentMidPoint( mPoints.last(), QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ), midPoint, mRadius, + mLastMouseMapPos ) ) + { + return; + } + + QList rubberBandPoints = mPoints; rubberBandPoints.append( midPoint ); rubberBandPoints.append( QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ) ); + QgsCircularStringV2* cString = new QgsCircularStringV2(); + cString->setPoints( rubberBandPoints ); + delete mRubberBand; + mRubberBand = createGeometryRubberBand(( mCaptureMode == CapturePolygon ) ? QGis::Polygon : QGis::Line ); + mRubberBand->setGeometry( cString ); + mRubberBand->show(); +} + +void QgsMapToolCircularStringRadius::createRadiusSpinBox() +{ + deleteRadiusSpinBox(); + mRadiusSpinBox = new QDoubleSpinBox(); + mRadiusSpinBox->setMaximum( 99999999 ); + mRadiusSpinBox->setDecimals( 2 ); + mRadiusSpinBox->setPrefix( tr( "Radius: " ) ); + mRadiusSpinBox->setValue( mRadius ); + QgisApp::instance()->addUserInputWidget( mRadiusSpinBox ); + QObject::connect( mRadiusSpinBox, SIGNAL( valueChanged( double ) ), this, SLOT( updateRadiusFromSpinBox( double ) ) ); + mRadiusSpinBox->setFocus( Qt::TabFocusReason ); +} + +void QgsMapToolCircularStringRadius::deleteRadiusSpinBox() +{ + if ( !mRadiusSpinBox ) + { + return; + } + QgisApp::instance()->statusBar()->removeWidget( mRadiusSpinBox ); + delete mRadiusSpinBox; mRadiusSpinBox = 0; +} + +void QgsMapToolCircularStringRadius::updateRadiusFromSpinBox( double radius ) +{ + mRadius = radius; + recalculateCircularString(); +} diff --git a/src/app/qgsmaptoolcircularstringradius.h b/src/app/qgsmaptoolcircularstringradius.h new file mode 100644 index 000000000000..686936485f44 --- /dev/null +++ b/src/app/qgsmaptoolcircularstringradius.h @@ -0,0 +1,52 @@ +/*************************************************************************** + qgsmaptoolcircularstringradius.h - map tool for adding circular strings + by two points and radius + --------------------- + begin : Feb 2015 + copyright : (C) 2015 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLCIRCULARSTRINGRADIUS_H +#define QGSMAPTOOLCIRCULARSTRINGRADIUS_H + +#include "qgsmaptooladdcircularstring.h" +#include "qgspointv2.h" + +class QDoubleSpinBox; + +class QgsMapToolCircularStringRadius: public QgsMapToolAddCircularString +{ + Q_OBJECT + public: + QgsMapToolCircularStringRadius( QgsMapToolCapture* parentTool, QgsMapCanvas* canvas, CaptureMode mode = CaptureLine ); + ~QgsMapToolCircularStringRadius(); + + virtual void canvasMapReleaseEvent( QgsMapMouseEvent* e ) override; + virtual void canvasMapMoveEvent( QgsMapMouseEvent* e ) override; + + private slots: + void updateRadiusFromSpinBox( double radius ); + + private: + double mTemporaryEndPointX; + double mTemporaryEndPointY; + bool mRadiusMode; + double mRadius; + QgsPointV2 mLastMouseMapPos; + QDoubleSpinBox* mRadiusSpinBox; + + //recalculate circular string and rubber band depending on mRadius/mLeft and endpoints + void recalculateCircularString(); + void createRadiusSpinBox(); + void deleteRadiusSpinBox(); +}; + +#endif // QGSMAPTOOLCIRCULARSTRINGRADIUS_H diff --git a/src/app/qgsmaptooledit.cpp b/src/app/qgsmaptooledit.cpp index 4a3a4fbf2e18..693eb1dc22fd 100644 --- a/src/app/qgsmaptooledit.cpp +++ b/src/app/qgsmaptooledit.cpp @@ -16,6 +16,7 @@ #include "qgsmaptooledit.h" #include "qgsproject.h" #include "qgsmapcanvas.h" +#include "qgsgeometryrubberband.h" #include "qgsrubberband.h" #include "qgsvectorlayer.h" @@ -97,6 +98,21 @@ int QgsMapToolEdit::addTopologicalPoints( const QList& geom ) return 0; } +QgsGeometryRubberBand* QgsMapToolEdit::createGeometryRubberBand( QGis::GeometryType geometryType ) const +{ + QSettings settings; + QgsGeometryRubberBand* rb = new QgsGeometryRubberBand( mCanvas, geometryType ); + QColor color( settings.value( "/qgis/digitizing/line_color_red", 255 ).toInt(), + settings.value( "/qgis/digitizing/line_color_green", 0 ).toInt(), + settings.value( "/qgis/digitizing/line_color_blue", 0 ).toInt() ); + double myAlpha = settings.value( "/qgis/digitizing/line_color_alpha", 200 ).toInt() / 255.0 ; + color.setAlphaF( myAlpha ); + rb->setOutlineColor( color ); + rb->setFillColor( color ); + rb->show(); + return rb; +} + void QgsMapToolEdit::notifyNotVectorLayer() { emit messageEmitted( tr( "No active vector layer" ) ); diff --git a/src/app/qgsmaptooledit.h b/src/app/qgsmaptooledit.h index eec30d28166f..4f3b15caada6 100644 --- a/src/app/qgsmaptooledit.h +++ b/src/app/qgsmaptooledit.h @@ -20,6 +20,7 @@ #include "qgsmaptooladvanceddigitizing.h" class QgsRubberBand; +class QgsGeometryRubberBand; class QgsVectorLayer; class QKeyEvent; @@ -44,6 +45,9 @@ class APP_EXPORT QgsMapToolEdit: public QgsMapToolAdvancedDigitizing */ QgsRubberBand* createRubberBand( QGis::GeometryType geometryType = QGis::Line, bool alternativeBand = false ); + + QgsGeometryRubberBand* createGeometryRubberBand( QGis::GeometryType geometryType = QGis::Line ) const; + /** Returns the current vector layer of the map canvas or 0*/ QgsVectorLayer* currentVectorLayer(); diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index d260faa26fbb..d6a01941e971 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -16,6 +16,7 @@ email : marco.hugentobler at sourcepole dot com #ifndef QGSABSTRACTGEOMETRYV2 #define QGSABSTRACTGEOMETRYV2 +#include "qgscoordinatetransform.h" #include "qgsrectangle.h" #include "qgswkbtypes.h" #include @@ -216,8 +217,9 @@ class CORE_EXPORT QgsAbstractGeometryV2 /** Transforms the geometry using a coordinate transform * @param ct coordinate transform + @param d transformation direction */ - virtual void transform( const QgsCoordinateTransform& ct ) = 0; + virtual void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) = 0; /** Transforms the geometry using a QTransform object * @param t QTransform transformation diff --git a/src/core/geometry/qgscircularstringv2.cpp b/src/core/geometry/qgscircularstringv2.cpp index d849c14ff2e5..ecedacfdf445 100644 --- a/src/core/geometry/qgscircularstringv2.cpp +++ b/src/core/geometry/qgscircularstringv2.cpp @@ -577,7 +577,7 @@ void QgsCircularStringV2::draw( QPainter& p ) const p.drawPath( path ); } -void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct ) +void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { double* zArray = mZ.data(); @@ -591,7 +591,7 @@ void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct ) zArray[i] = 0; } } - ct.transformCoords( nPoints, mX.data(), mY.data(), zArray ); + ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d ); if ( !hasZ ) { delete[] zArray; diff --git a/src/core/geometry/qgscircularstringv2.h b/src/core/geometry/qgscircularstringv2.h index 07e0d1258454..e1f0bb7ab9d5 100644 --- a/src/core/geometry/qgscircularstringv2.h +++ b/src/core/geometry/qgscircularstringv2.h @@ -68,7 +68,11 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2 virtual QgsLineStringV2* curveToLine() const override; void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; #if 0 void clip( const QgsRectangle& rect ) override; diff --git a/src/core/geometry/qgscompoundcurvev2.cpp b/src/core/geometry/qgscompoundcurvev2.cpp index e34ac10764c2..a8fc5b540156 100644 --- a/src/core/geometry/qgscompoundcurvev2.cpp +++ b/src/core/geometry/qgscompoundcurvev2.cpp @@ -410,12 +410,12 @@ void QgsCompoundCurveV2::draw( QPainter& p ) const } } -void QgsCompoundCurveV2::transform( const QgsCoordinateTransform& ct ) +void QgsCompoundCurveV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { QList< QgsCurveV2* >::iterator it = mCurves.begin(); for ( ; it != mCurves.end(); ++it ) { - ( *it )->transform( ct ); + ( *it )->transform( ct, d ); } } diff --git a/src/core/geometry/qgscompoundcurvev2.h b/src/core/geometry/qgscompoundcurvev2.h index ed9aa9637dcc..b62d23fd482f 100644 --- a/src/core/geometry/qgscompoundcurvev2.h +++ b/src/core/geometry/qgscompoundcurvev2.h @@ -81,7 +81,11 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2 void addVertex( const QgsPointV2& pt ); void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; void addToPainterPath( QPainterPath& path ) const override; void drawAsPolygon( QPainter& p ) const override; diff --git a/src/core/geometry/qgscurvepolygonv2.cpp b/src/core/geometry/qgscurvepolygonv2.cpp index e36be38cf0e1..eac17e0603c7 100644 --- a/src/core/geometry/qgscurvepolygonv2.cpp +++ b/src/core/geometry/qgscurvepolygonv2.cpp @@ -474,17 +474,17 @@ void QgsCurvePolygonV2::draw( QPainter& p ) const } } -void QgsCurvePolygonV2::transform( const QgsCoordinateTransform& ct ) +void QgsCurvePolygonV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { if ( mExteriorRing ) { - mExteriorRing->transform( ct ); + mExteriorRing->transform( ct, d ); } QList::iterator it = mInteriorRings.begin(); for ( ; it != mInteriorRings.end(); ++it ) { - ( *it )->transform( ct ); + ( *it )->transform( ct, d ); } } diff --git a/src/core/geometry/qgscurvepolygonv2.h b/src/core/geometry/qgscurvepolygonv2.h index 009b9b6c3988..b7b1cb2b1d19 100644 --- a/src/core/geometry/qgscurvepolygonv2.h +++ b/src/core/geometry/qgscurvepolygonv2.h @@ -76,7 +76,11 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2 bool removeInteriorRing( int nr ); virtual void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; virtual bool insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ) override; diff --git a/src/core/geometry/qgsgeometrycollectionv2.cpp b/src/core/geometry/qgsgeometrycollectionv2.cpp index e600ab1a2b49..28a2f6d7c1ad 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.cpp +++ b/src/core/geometry/qgsgeometrycollectionv2.cpp @@ -130,12 +130,12 @@ int QgsGeometryCollectionV2::dimension() const return maxDim; } -void QgsGeometryCollectionV2::transform( const QgsCoordinateTransform& ct ) +void QgsGeometryCollectionV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { QVector< QgsAbstractGeometryV2* >::iterator it = mGeometries.begin(); for ( ; it != mGeometries.end(); ++it ) { - ( *it )->transform( ct ); + ( *it )->transform( ct, d ); } } diff --git a/src/core/geometry/qgsgeometrycollectionv2.h b/src/core/geometry/qgsgeometrycollectionv2.h index 0c609ffce281..66e43272f5fb 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.h +++ b/src/core/geometry/qgsgeometrycollectionv2.h @@ -63,7 +63,11 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2 */ virtual bool removeGeometry( int nr ); - virtual void transform( const QgsCoordinateTransform& ct ) override; + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + virtual void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; #if 0 virtual void clip( const QgsRectangle& rect ) override; diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp index a64ee9949113..7e675db57b44 100644 --- a/src/core/geometry/qgslinestringv2.cpp +++ b/src/core/geometry/qgslinestringv2.cpp @@ -333,9 +333,9 @@ void QgsLineStringV2::drawAsPolygon( QPainter& p ) const p.drawPolygon( mCoords ); } -void QgsLineStringV2::transform( const QgsCoordinateTransform& ct ) +void QgsLineStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { - ct.transformPolygon( mCoords ); + ct.transformPolygon( mCoords, d ); } void QgsLineStringV2::transform( const QTransform& t ) diff --git a/src/core/geometry/qgslinestringv2.h b/src/core/geometry/qgslinestringv2.h index f0ddced09f6c..98c2c15b1742 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -64,7 +64,12 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2 void append( const QgsLineStringV2* line ); void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; void addToPainterPath( QPainterPath& path ) const override; diff --git a/src/core/geometry/qgspointv2.cpp b/src/core/geometry/qgspointv2.cpp index 8d479f8467e7..54b89b37d4cb 100644 --- a/src/core/geometry/qgspointv2.cpp +++ b/src/core/geometry/qgspointv2.cpp @@ -181,9 +181,9 @@ void QgsPointV2::clear() mX = mY = mZ = mM = 0.; } -void QgsPointV2::transform( const QgsCoordinateTransform& ct ) +void QgsPointV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { - ct.transformInPlace( mX, mY, mZ ); + ct.transformInPlace( mX, mY, mZ, d ); } void QgsPointV2::coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord ) const diff --git a/src/core/geometry/qgspointv2.h b/src/core/geometry/qgspointv2.h index cfd96d20d1fa..59164ea0d6cb 100644 --- a/src/core/geometry/qgspointv2.h +++ b/src/core/geometry/qgspointv2.h @@ -67,7 +67,12 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 virtual QgsRectangle calculateBoundingBox() const override { return QgsRectangle( mX, mY, mX, mY );} void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + + /** Transforms the geometry using a coordinate transform + * @param ct coordinate transform + @param d transformation direction + */ + void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord ) const override; diff --git a/src/core/qgsvectordataprovider.h b/src/core/qgsvectordataprovider.h index c6edb225ca5c..93df50adf7bf 100644 --- a/src/core/qgsvectordataprovider.h +++ b/src/core/qgsvectordataprovider.h @@ -94,7 +94,9 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider /** Supports topological simplification of geometries on provider side according to a distance tolerance */ SimplifyGeometriesWithTopologicalValidation = 1 << 15, /** Supports transactions*/ - TransactionSupport = 1 << 16 + TransactionSupport = 1 << 16, + /** Supports circular geometry types (circularstring, compoundcurve, curvepolygon)*/ + CircularGeometries = 1 << 17 }; /** Bitmask of all provider's editing capabilities */ diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index d8ae91c22ce8..b1c7d765b904 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -40,6 +40,7 @@ #include "qgsclipper.h" #include "qgscoordinatereferencesystem.h" #include "qgscoordinatetransform.h" +#include "qgscurvev2.h" #include "qgsdatasourceuri.h" #include "qgsexpressionfieldbuffer.h" #include "qgsfeature.h" @@ -1043,6 +1044,27 @@ int QgsVectorLayer::addRing( const QList& ring ) return utils.addRing( ring ); } +int QgsVectorLayer::addRing( QgsCurveV2* ring ) +{ + if ( !mEditBuffer || !mDataProvider ) + { + return 6; + } + + if ( !ring ) + { + return 1; + } + + if ( !ring->isClosed() ) + { + delete ring; return 2; + } + + QgsVectorLayerEditUtils utils( this ); + return utils.addRing( ring ); +} + int QgsVectorLayer::addPart( const QList &points ) { if ( !mEditBuffer || !mDataProvider ) @@ -1065,6 +1087,27 @@ int QgsVectorLayer::addPart( const QList &points ) return utils.addPart( points, *mSelectedFeatureIds.constBegin() ); } +int QgsVectorLayer::addPart( QgsCurveV2* ring ) +{ + if ( !mEditBuffer || !mDataProvider ) + return 7; + + //number of selected features must be 1 + + if ( mSelectedFeatureIds.size() < 1 ) + { + QgsDebugMsg( "Number of selected features <1" ); + return 4; + } + else if ( mSelectedFeatureIds.size() > 1 ) + { + QgsDebugMsg( "Number of selected features >1" ); + return 5; + } + + QgsVectorLayerEditUtils utils( this ); + return utils.addPart( ring, *mSelectedFeatureIds.constBegin() ); +} int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy ) { @@ -2229,7 +2272,7 @@ bool QgsVectorLayer::deleteAttributes( QList attrs ) qSort( attrs.begin(), attrs.end(), qGreater() ); - Q_FOREACH ( int attr, attrs ) + Q_FOREACH( int attr, attrs ) { if ( deleteAttribute( attr ) ) { @@ -2988,7 +3031,7 @@ void QgsVectorLayer::uniqueValues( int index, QList &uniqueValues, int if ( mEditBuffer ) { QSet vals; - Q_FOREACH ( const QVariant& v, uniqueValues ) + Q_FOREACH( const QVariant& v, uniqueValues ) { vals << v.toString(); } @@ -3818,7 +3861,7 @@ void QgsVectorLayer::invalidateSymbolCountedFlag() void QgsVectorLayer::onRelationsLoaded() { - Q_FOREACH ( QgsAttributeEditorElement* elem, mAttributeEditorElements ) + Q_FOREACH( QgsAttributeEditorElement* elem, mAttributeEditorElements ) { if ( elem->type() == QgsAttributeEditorElement::AeTypeContainer ) { @@ -3827,7 +3870,7 @@ void QgsVectorLayer::onRelationsLoaded() continue; QList relations = cont->findElements( QgsAttributeEditorElement::AeTypeRelation ); - Q_FOREACH ( QgsAttributeEditorElement* relElem, relations ) + Q_FOREACH( QgsAttributeEditorElement* relElem, relations ) { QgsAttributeEditorRelation* rel = dynamic_cast< QgsAttributeEditorRelation* >( relElem ); if ( !rel ) @@ -3896,7 +3939,7 @@ QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const QDomElement elem = doc.createElement( "attributeEditorContainer" ); elem.setAttribute( "name", mName ); - Q_FOREACH ( QgsAttributeEditorElement* child, mChildren ) + Q_FOREACH( QgsAttributeEditorElement* child, mChildren ) { elem.appendChild( child->toDomElement( doc ) ); } @@ -3917,7 +3960,7 @@ QList QgsAttributeEditorContainer::findElements( Qgs { QList results; - Q_FOREACH ( QgsAttributeEditorElement* elem, mChildren ) + Q_FOREACH( QgsAttributeEditorElement* elem, mChildren ) { if ( elem->type() == type ) { diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 73857c0407ad..43b1312cb087 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -42,6 +42,7 @@ class QgsAbstractGeometrySimplifier; class QgsAttributeAction; class QgsFieldUIProperties; class QgsCoordinateTransform; +class QgsCurveV2; class QgsDiagramLayerSettings; class QgsDiagramRendererV2; class QgsEditorWidgetWrapper; @@ -1170,6 +1171,14 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer 6 layer not editable */ int addRing( const QList& ring ); + /** Adds a ring to polygon/multipolygon features (takes ownership) + @return + 0 in case of success + 1 problem with feature type + 2 ring not closed + 6 layer not editable*/ + int addRing( QgsCurveV2* ring ); + /** Adds a new part polygon to a multipart feature @return 0 in case of success, @@ -1182,6 +1191,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer 7 layer not editable */ int addPart( const QList& ring ); + int addPart( QgsCurveV2* ring ); + /** Translates feature by dx, dy @param featureId id of the feature to translate @param dx translation of x-coordinate diff --git a/src/core/qgsvectorlayereditutils.cpp b/src/core/qgsvectorlayereditutils.cpp index 566a93005def..47f8522f6db1 100644 --- a/src/core/qgsvectorlayereditutils.cpp +++ b/src/core/qgsvectorlayereditutils.cpp @@ -17,6 +17,7 @@ #include "qgsvectordataprovider.h" #include "qgsgeometrycache.h" #include "qgsvectorlayereditbuffer.h" +#include "qgslinestringv2.h" #include "qgslogger.h" #include "qgspointv2.h" @@ -103,26 +104,26 @@ bool QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId atFeatureId, int atVert return true; } - int QgsVectorLayerEditUtils::addRing( const QList& ring ) +{ + QgsLineStringV2* ringLine = new QgsLineStringV2(); + QList< QgsPointV2 > ringPoints; + QList::const_iterator ringIt = ring.constBegin(); + for ( ; ringIt != ring.constEnd(); ++ringIt ) + { + ringPoints.append( QgsPointV2( ringIt->x(), ringIt->y() ) ); + } + ringLine->setPoints( ringPoints ); + return addRing( ringLine ); +} + +int QgsVectorLayerEditUtils::addRing( QgsCurveV2* ring ) { if ( !L->hasGeometryType() ) return 5; int addRingReturnCode = 5; //default: return code for 'ring not inserted' - double xMin, yMin, xMax, yMax; - QgsRectangle bBox; - - if ( boundingBoxFromPointList( ring, xMin, yMin, xMax, yMax ) == 0 ) - { - bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); - bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); - } - else - { - return 3; //ring not valid - } - + QgsRectangle bBox = ring->boundingBox(); QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; @@ -141,7 +142,6 @@ int QgsVectorLayerEditUtils::addRing( const QList& ring ) return addRingReturnCode; } - int QgsVectorLayerEditUtils::addPart( const QList &points, QgsFeatureId featureId ) { if ( !L->hasGeometryType() ) @@ -152,10 +152,10 @@ int QgsVectorLayerEditUtils::addPart( const QList &points, QgsFeatureI { // it's not in cache: let's fetch it from layer QgsFeature f; - if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.constGeometry() ) + if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.geometry() ) return 6; //geometry not found - geometry = *f.constGeometry(); + geometry = *f.geometry(); } int errorCode = geometry.addPart( points, L->geometryType() ); @@ -166,6 +166,29 @@ int QgsVectorLayerEditUtils::addPart( const QList &points, QgsFeatureI return errorCode; } +int QgsVectorLayerEditUtils::addPart( QgsCurveV2* ring, QgsFeatureId featureId ) +{ + if ( !L->hasGeometryType() ) + return 6; + + QgsGeometry geometry; + if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache + { + // it's not in cache: let's fetch it from layer + QgsFeature f; + if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.geometry() ) + return 6; //geometry not found + + geometry = *f.geometry(); + } + + int errorCode = geometry.addPart( ring ); + if ( errorCode == 0 ) + { + L->editBuffer()->changeGeometry( featureId, &geometry ); + } + return errorCode; +} int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy ) diff --git a/src/core/qgsvectorlayereditutils.h b/src/core/qgsvectorlayereditutils.h index 20c64114af01..734ed6774b94 100644 --- a/src/core/qgsvectorlayereditutils.h +++ b/src/core/qgsvectorlayereditutils.h @@ -21,6 +21,7 @@ #include "qgsvectorlayer.h" class QgsGeometryCache; +class QgsCurveV2; class CORE_EXPORT QgsVectorLayerEditUtils { @@ -62,6 +63,16 @@ class CORE_EXPORT QgsVectorLayerEditUtils 5 no feature found where ring can be inserted*/ int addRing( const QList& ring ); + /** Adds a ring to polygon/multipolygon features + @return + 0 in case of success, + 1 problem with feature type, + 2 ring not closed, + 3 ring not valid, + 4 ring crosses existing rings, + 5 no feature found where ring can be inserted*/ + int addRing( QgsCurveV2* ring ); + /** Adds a new part polygon to a multipart feature @return 0 in case of success, @@ -73,6 +84,8 @@ class CORE_EXPORT QgsVectorLayerEditUtils 6 if selected geometry not found*/ int addPart( const QList& ring, QgsFeatureId featureId ); + int addPart( QgsCurveV2* ring, QgsFeatureId featureId ); + /** Translates feature by dx, dy @param featureId id of the feature to translate @param dx translation of x-coordinate diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 0ef0e708b532..561bfb5d5b11 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -1095,6 +1095,9 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities() //supports transactions mEnabledCapabilities |= QgsVectorDataProvider::TransactionSupport; + + // supports circular geometries + mEnabledCapabilities |= QgsVectorDataProvider::CircularGeometries; return true; } diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui index 45b9acadfe8d..7ab40f7ffb47 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -17,7 +17,7 @@ 0 0 1050 - 25 + 20 @@ -356,6 +356,8 @@ + + @@ -2352,6 +2354,30 @@ Acts on currently active editable layer Align Rasters... + + + true + + + + :/images/themes/default/mActionCircularStringCurvePoint.png:/images/themes/default/mActionCircularStringCurvePoint.png + + + Add circular string + + + + + true + + + + :/images/themes/default/mActionCircularStringRadius.png:/images/themes/default/mActionCircularStringRadius.png + + + Add circular string by radius + +