diff --git a/images/images.qrc b/images/images.qrc index dbcf58aeb7e..b89f176311b 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -504,6 +504,7 @@ themes/default/mIconClear.png flags/zh.png themes/default/mIconPaintEffects.svg + themes/default/mActionCircularStringCurvePoint.png qgis_tips/symbol_levels.png diff --git a/python/core/geometry/qgsabstractgeometryv2.sip b/python/core/geometry/qgsabstractgeometryv2.sip index 54289f297f6..2439150fa56 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 48d312dd551..322d8d2c0e7 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 558a7cd8634..ed69bcd6bcd 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 8616636efbc..24db6e28685 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 3819ebe6319..5ea302a62b4 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 93830695272..93a2eadea62 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 bb8324713aa..22bf44538d9 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -117,6 +117,8 @@ SET(QGIS_APP_SRCS qgsvectorlayerproperties.cpp qgsvisibilitypresets.cpp qgshandlebadlayers.cpp + qgsmaptooladdcircularstring.cpp + qgsmaptoolcircularstringcurvepoint.cpp composer/qgsattributeselectiondialog.cpp composer/qgscomposer.cpp @@ -240,6 +242,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 d0d484c6049..245a4db94ad 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -250,6 +250,7 @@ #include "qgsmaptooladdring.h" #include "qgsmaptoolfillring.h" #include "qgsmaptoolannotation.h" +#include "qgsmaptoolcircularstringcurvepoint.h" #include "qgsmaptooldeletering.h" #include "qgsmaptooldeletepart.h" #include "qgsmaptoolfeatureaction.h" @@ -1170,6 +1171,7 @@ 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( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) ); connect( mActionRotateFeature, SIGNAL( triggered() ), this, SLOT( rotateFeature() ) ); @@ -1444,6 +1446,7 @@ void QgisApp::createActionGroups() mMapToolGroup->addAction( mActionMeasureArea ); mMapToolGroup->addAction( mActionMeasureAngle ); mMapToolGroup->addAction( mActionAddFeature ); + mMapToolGroup->addAction( mActionCircularStringCurvePoint ); mMapToolGroup->addAction( mActionMoveFeature ); mMapToolGroup->addAction( mActionRotateFeature ); #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ @@ -2293,6 +2296,8 @@ 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.mMoveFeature = new QgsMapToolMoveFeature( mMapCanvas ); mMapTools.mMoveFeature->setAction( mActionMoveFeature ); mMapTools.mRotateFeature = new QgsMapToolRotateFeature( mMapCanvas ); @@ -6159,6 +6164,11 @@ void QgisApp::addFeature() mMapCanvas->setMapTool( mMapTools.mAddFeature ); } +void QgisApp::circularStringCurvePoint() +{ + mMapCanvas->setMapTool( mMapTools.mCircularStringCurvePoint ); +} + void QgisApp::selectFeatures() { mMapCanvas->setMapTool( mMapTools.mSelectFeatures ); diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index daf1e42318e..490d4204b3d 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -966,6 +966,8 @@ 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 move feature tool void moveFeature(); //! activates the offset curve tool @@ -1471,6 +1473,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QgsMapTool *mMeasureArea; QgsMapTool *mMeasureAngle; QgsMapTool *mAddFeature; + QgsMapTool *mCircularStringCurvePoint; QgsMapTool *mMoveFeature; QgsMapTool *mOffsetCurve; QgsMapTool *mReshapeFeatures; diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 33edfc6b500..52f7adcbfee 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; + + QgsCurveV2* curveToAdd = 0; + if ( hasCurvedSegments && providerSupportsCurvedSegments ) + { + curveToAdd = dynamic_cast( captureCurve()->clone() ); + } + else + { + curveToAdd = captureCurve()->curveToLine(); + } if ( mode() == CaptureLine ) { - 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 - } - - f->setGeometry( g ); + 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 + poly = new QgsPolygonV2(); } - - if ( !g ) - { - stopCapturing(); - delete f; - return; // invalid geometry; one possibility is from duplicate points - } - 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 d0f9110d2fb..f861200255a 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" @@ -118,33 +121,52 @@ void QgsMapToolAddPart::canvasMapReleaseEvent( QgsMapMouseEvent * e ) if ( !isCapturing() ) return; - // we are now going to finish the capturing - if ( mode() == CapturePolygon ) { - //close polygon closePolygon(); - //avoid intersections - QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() ); - if ( geom ) - { - geom->avoidIntersections(); - QgsPolygon poly = geom->asPolygon(); - if ( poly.size() < 1 ) - { - stopCapturing(); - delete geom; - vlayer->destroyEditCommand(); - return; - } - setPoints( geom->asPolygon()[0].toList() ); - delete geom; - } + } + + //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" ) ); - errorCode = vlayer->addPart( points() ); + int errorCode = 0; + if ( mode() == CapturePolygon ) + { + //avoid intersections + QgsCurvePolygonV2* cp = new QgsCurvePolygonV2(); + cp->setExteriorRing( curveToAdd ); + QgsGeometry* geom = new QgsGeometry( cp ); + geom->avoidIntersections(); + const QgsCurvePolygonV2* cpGeom = dynamic_cast( geom->geometry() ); + if ( !cpGeom ) + { + stopCapturing(); + delete geom; + vlayer->destroyEditCommand(); + return; + } + + 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 15b0b84cb82..57ac4a2088e 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 2eee7af628a..0a4248fbe0c 100644 --- a/src/app/qgsmaptoolcapture.cpp +++ b/src/app/qgsmaptoolcapture.cpp @@ -169,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 ) @@ -219,9 +226,6 @@ int QgsMapToolCapture::addVertex( const QgsPoint& point ) int QgsMapToolCapture::addCurve( QgsCurveV2* c ) { - return 1; //todo... - -#if 0 if ( !c ) { return 1; @@ -253,12 +257,16 @@ int QgsMapToolCapture::addCurve( QgsCurveV2* c ) QgsPointV2 endPt = c->endPoint(); mTempRubberBand->addPoint( QgsPoint( endPt.x(), endPt.y() ) ); //add last point of c - //const QgsCoordinateTransform* ct = mapCanvas()->mapSettings()->layerTransform( QgsMapLayer *layer ) const - //c->transform( ct, QgsCoordinateTransform::ReverseTransform); - //mCaptureCurve.addCurve( transformed curve ); + //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; -#endif //0 } diff --git a/src/app/qgsmaptoolcapture.h b/src/app/qgsmaptoolcapture.h index 7149238cc63..739b485c15a 100644 --- a/src/app/qgsmaptoolcapture.h +++ b/src/app/qgsmaptoolcapture.h @@ -53,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 ); @@ -60,14 +65,12 @@ 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*/ int addVertex( const QgsPoint& point ); - /** Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be in map CRS*/ - int addCurve( QgsCurveV2* c ); - /** Removes the last vertex from mRubberBand and mCaptureList*/ void undo(); diff --git a/src/app/qgsmaptooledit.cpp b/src/app/qgsmaptooledit.cpp index 4a3a4fbf2e1..693eb1dc22f 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 eec30d28166..4f3b15caada 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 d260faa26fb..1766f38c24f 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 @@ -217,7 +218,7 @@ class CORE_EXPORT QgsAbstractGeometryV2 /** Transforms the geometry using a coordinate transform * @param ct coordinate transform */ - 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 d849c14ff2e..ecedacfdf44 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 07e0d125845..4435c034777 100644 --- a/src/core/geometry/qgscircularstringv2.h +++ b/src/core/geometry/qgscircularstringv2.h @@ -68,7 +68,7 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2 virtual QgsLineStringV2* curveToLine() const override; void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + 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 e34ac10764c..a8fc5b54015 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 ed9aa9637dc..e69003d7493 100644 --- a/src/core/geometry/qgscompoundcurvev2.h +++ b/src/core/geometry/qgscompoundcurvev2.h @@ -81,7 +81,7 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2 void addVertex( const QgsPointV2& pt ); void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + 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 e36be38cf0e..eac17e0603c 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 009b9b6c398..e8a11376a10 100644 --- a/src/core/geometry/qgscurvepolygonv2.h +++ b/src/core/geometry/qgscurvepolygonv2.h @@ -76,7 +76,7 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2 bool removeInteriorRing( int nr ); virtual void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + 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 e600ab1a2b4..28a2f6d7c1a 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 0c609ffce28..ec13e27c80a 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.h +++ b/src/core/geometry/qgsgeometrycollectionv2.h @@ -63,7 +63,7 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2 */ virtual bool removeGeometry( int nr ); - virtual void transform( const QgsCoordinateTransform& ct ) override; + 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 a64ee994911..7e675db57b4 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 f0ddced09f6..cf8d379a47e 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -64,7 +64,7 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2 void append( const QgsLineStringV2* line ); void draw( QPainter& p ) const override; - void transform( const QgsCoordinateTransform& ct ) override; + 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 8d479f8467e..54b89b37d4c 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 cfd96d20d1f..b1ab89fa774 100644 --- a/src/core/geometry/qgspointv2.h +++ b/src/core/geometry/qgspointv2.h @@ -67,7 +67,7 @@ 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; + 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 c6edb225ca5..93df50adf7b 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 d5fbe3714d3..1e3e5578f0c 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" @@ -1036,6 +1037,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 ) @@ -1058,6 +1080,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 ) { @@ -2182,7 +2225,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 ) ) { @@ -2941,7 +2984,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(); } @@ -3757,7 +3800,7 @@ void QgsVectorLayer::invalidateSymbolCountedFlag() void QgsVectorLayer::onRelationsLoaded() { - Q_FOREACH ( QgsAttributeEditorElement* elem, mAttributeEditorElements ) + Q_FOREACH( QgsAttributeEditorElement* elem, mAttributeEditorElements ) { if ( elem->type() == QgsAttributeEditorElement::AeTypeContainer ) { @@ -3766,7 +3809,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 ) @@ -3835,7 +3878,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 ) ); } @@ -3856,7 +3899,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 c8c8b6cc008..2cbce3529c5 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -40,6 +40,7 @@ class QImage; class QgsAbstractGeometrySimplifier; class QgsAttributeAction; class QgsCoordinateTransform; +class QgsCurveV2; class QgsDiagramLayerSettings; class QgsDiagramRendererV2; class QgsEditorWidgetWrapper; @@ -1165,6 +1166,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, @@ -1177,6 +1186,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 566a93005de..47f8522f6db 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 20c64114af0..734ed6774b9 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 c97308b4ebb..b7c70e9faaf 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -1091,6 +1091,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 45b9acadfe8..44f82eb608f 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -17,7 +17,7 @@ 0 0 1050 - 25 + 20 @@ -356,6 +356,7 @@ + @@ -2352,6 +2353,18 @@ Acts on currently active editable layer Align Rasters... + + + true + + + + :/images/themes/default/mActionCircularStringCurvePoint.png:/images/themes/default/mActionCircularStringCurvePoint.png + + + Add circular string + +