Merge pull request #2268 from mhugent/curve_capture_tool

Curve capture tool
This commit is contained in:
mhugent 2015-08-24 18:18:40 +02:00
commit 5807875797
45 changed files with 1028 additions and 126 deletions

View File

@ -508,6 +508,8 @@
<file>themes/default/mIconClear.png</file>
<file>flags/zh.png</file>
<file>themes/default/mIconPaintEffects.svg</file>
<file>themes/default/mActionCircularStringCurvePoint.png</file>
<file>themes/default/mActionCircularStringRadius.png</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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<QgsMapToolAddFeature*>( mMapTools.mAddFeature ), mMapCanvas );
mMapTools.mCircularStringCurvePoint->setAction( mActionCircularStringCurvePoint );
mMapTools.mCircularStringRadius = new QgsMapToolCircularStringRadius( dynamic_cast<QgsMapToolAddFeature*>( 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 );

View File

@ -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;

View File

@ -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 <QMouseEvent>
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<QgsMapToolCapture*>( oldTool );
QgsMapToolAddCircularString* csTool = dynamic_cast<QgsMapToolAddCircularString*>( 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;
}

View File

@ -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

View File

@ -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<QgsCurveV2*>( 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 )

View File

@ -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();
//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<QgsCurveV2*>( captureCurve()->clone() );
}
else
{
curveToAdd = captureCurve()->curveToLine();
}
vlayer->beginEditCommand( tr( "Part added" ) );
errorCode = vlayer->addPart( points() );
if ( mode() == CapturePolygon )
{
//avoid intersections
QgsCurvePolygonV2* cp = new QgsCurvePolygonV2();
cp->setExteriorRing( curveToAdd );
QgsGeometry* geom = new QgsGeometry( cp );
geom->avoidIntersections();
const QgsCurvePolygonV2* cpGeom = dynamic_cast<const QgsCurvePolygonV2*>( geom->geometry() );
if ( !cpGeom )
{
stopCapturing();
delete geom;
vlayer->destroyEditCommand();
return;
}
errorCode = vlayer->addPart( dynamic_cast<QgsCurveV2*>( cpGeom->exteriorRing()->clone() ) );
delete geom;
}
else
{
errorCode = vlayer->addPart( curveToAdd );
}
stopCapturing();
}
break;

View File

@ -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<QgsCurveV2*>( captureCurve()->clone() );
}
else
{
curveToAdd = captureCurve()->curveToLine();
}
int addRingReturnCode = vlayer->addRing( curveToAdd );
if ( addRingReturnCode != 0 )
{
QString errorMessage;

View File

@ -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<QgsPointV2> linePoints;
lineString->points( linePoints );
delete lineString;
QList<QgsPointV2>::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<QgsVectorLayer *>( 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<QgsPoint> QgsMapToolCapture::points()
{
QList<QgsPointV2> pts;
QList<QgsPoint> points;
mCaptureCurve.points( pts );
QgsGeometry::convertPointList( pts, points );
return points;
}
void QgsMapToolCapture::setPoints( const QList<QgsPoint>& pointList )
{
QList<QgsPointV2> pts;
QgsGeometry::convertPointList( pointList, pts );
QgsLineStringV2* line = new QgsLineStringV2();
line->setPoints( pts );
mCaptureCurve.clear();
mCaptureCurve.addCurve( line );
}

View File

@ -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<QgsPoint>::iterator begin() { return mCaptureList.begin(); }
QList<QgsPoint>::iterator end() { return mCaptureList.end(); }
const QList<QgsPoint> &points() { return mCaptureList; }
void setPoints( const QList<QgsPoint>& pointList ) { mCaptureList = pointList; }
int size();
QList<QgsPoint> points();
void setPoints( const QList<QgsPoint>& 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<QgsPoint> mCaptureList;
QgsCompoundCurveV2 mCaptureCurve;
void validateGeometry();
QString mTip;

View File

@ -0,0 +1,87 @@
#include "qgsmaptoolcircularstringcurvepoint.h"
#include "qgscircularstringv2.h"
#include "qgscompoundcurvev2.h"
#include "qgsgeometryrubberband.h"
#include "qgsmapcanvas.h"
#include "qgspointv2.h"
#include <QMouseEvent>
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 );
}
}

View File

@ -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

View File

@ -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 <QDoubleSpinBox>
#include <QMouseEvent>
#include <cmath>
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<QgsPointV2> 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();
}

View File

@ -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

View File

@ -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<QgsPoint>& 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" ) );

View File

@ -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();

View File

@ -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 <QString>
@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -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<QgsCurveV2*>::iterator it = mInteriorRings.begin();
for ( ; it != mInteriorRings.end(); ++it )
{
( *it )->transform( ct );
( *it )->transform( ct, d );
}
}

View File

@ -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;

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -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 )

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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<QgsPoint>& 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<QgsPoint> &points )
{
if ( !mEditBuffer || !mDataProvider )
@ -1065,6 +1087,27 @@ int QgsVectorLayer::addPart( const QList<QgsPoint> &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<int> attrs )
qSort( attrs.begin(), attrs.end(), qGreater<int>() );
Q_FOREACH ( int attr, attrs )
Q_FOREACH( int attr, attrs )
{
if ( deleteAttribute( attr ) )
{
@ -2988,7 +3031,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
if ( mEditBuffer )
{
QSet<QString> 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<QgsAttributeEditorElement*> 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<QgsAttributeEditorElement*> QgsAttributeEditorContainer::findElements( Qgs
{
QList<QgsAttributeEditorElement*> results;
Q_FOREACH ( QgsAttributeEditorElement* elem, mChildren )
Q_FOREACH( QgsAttributeEditorElement* elem, mChildren )
{
if ( elem->type() == type )
{

View File

@ -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<QgsPoint>& 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<QgsPoint>& ring );
int addPart( QgsCurveV2* ring );
/** Translates feature by dx, dy
@param featureId id of the feature to translate
@param dx translation of x-coordinate

View File

@ -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<QgsPoint>& ring )
{
QgsLineStringV2* ringLine = new QgsLineStringV2();
QList< QgsPointV2 > ringPoints;
QList<QgsPoint>::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<QgsPoint>& ring )
return addRingReturnCode;
}
int QgsVectorLayerEditUtils::addPart( const QList<QgsPoint> &points, QgsFeatureId featureId )
{
if ( !L->hasGeometryType() )
@ -152,10 +152,10 @@ int QgsVectorLayerEditUtils::addPart( const QList<QgsPoint> &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<QgsPoint> &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 )

View File

@ -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<QgsPoint>& 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<QgsPoint>& 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

View File

@ -1095,6 +1095,9 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
//supports transactions
mEnabledCapabilities |= QgsVectorDataProvider::TransactionSupport;
// supports circular geometries
mEnabledCapabilities |= QgsVectorDataProvider::CircularGeometries;
return true;
}

View File

@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1050</width>
<height>25</height>
<height>20</height>
</rect>
</property>
<property name="toolTip">
@ -356,6 +356,8 @@
<addaction name="mActionToggleEditing"/>
<addaction name="mActionSaveLayerEdits"/>
<addaction name="mActionAddFeature"/>
<addaction name="mActionCircularStringCurvePoint"/>
<addaction name="mActionCircularStringRadius"/>
<addaction name="mActionMoveFeature"/>
<addaction name="mActionNodeTool"/>
<addaction name="mActionDeleteSelected"/>
@ -2352,6 +2354,30 @@ Acts on currently active editable layer</string>
<string>Align Rasters...</string>
</property>
</action>
<action name="mActionCircularStringCurvePoint">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionCircularStringCurvePoint.png</normaloff>:/images/themes/default/mActionCircularStringCurvePoint.png</iconset>
</property>
<property name="text">
<string>Add circular string</string>
</property>
</action>
<action name="mActionCircularStringRadius">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionCircularStringRadius.png</normaloff>:/images/themes/default/mActionCircularStringRadius.png</iconset>
</property>
<property name="text">
<string>Add circular string by radius</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>