Merge pull request #7659 from lbartoletti/reverseLine

[needs-docs][FEATURE] Add reverse line maptools AKA swap direction
This commit is contained in:
Nyall Dawson 2018-09-05 08:59:49 +10:00 committed by GitHub
commit e10d16e1da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 607 additions and 0 deletions

View File

@ -704,6 +704,7 @@
<file>themes/default/mIconGPU.svg</file> <file>themes/default/mIconGPU.svg</file>
<file>themes/default/mAddToProject.svg</file> <file>themes/default/mAddToProject.svg</file>
<file>themes/default/mDockify.svg</file> <file>themes/default/mDockify.svg</file>
<file>themes/default/mActionReverseLine.svg</file>
<file>themes/default/mActionAdd3DMap.svg</file> <file>themes/default/mActionAdd3DMap.svg</file>
</qresource> </qresource>
<qresource prefix="/images/tips"> <qresource prefix="/images/tips">

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
viewBox="0 0 24 24"
width="24"
version="1.1"
id="svg28"
sodipodi:docname="mActionReverseLine.svg"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
<metadata
id="metadata34">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs32" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1025"
id="namedview30"
showgrid="false"
inkscape:zoom="19.666667"
inkscape:cx="-2.3885008"
inkscape:cy="4.628421"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1"
inkscape:current-layer="svg28" />
<linearGradient
gradientUnits="userSpaceOnUse"
x1="50.5"
x2="50.5"
y1="16.9999985"
y2="22.9999985"
id="linearGradient6">
<stop
offset="0"
stop-color="#555753"
id="stop2" />
<stop
offset="1"
stop-color="#555753"
stop-opacity="0"
id="stop4" />
</linearGradient>
<g
id="g908">
<path
d="M 2.5,2.5 9,15 15,5 h 6"
id="path8"
inkscape:connector-curvature="0"
style="fill:none;stroke:#8cbe8c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round" />
<path
d="m 1.5,1.5 h 3 v 3 h -3 z"
id="path10"
inkscape:connector-curvature="0"
style="fill:#bebebe;stroke:#8c8c8c;stroke-width:0.99999994" />
<path
d="m 7.5,13.5 h 3 v 3 h -3 z"
id="path12"
inkscape:connector-curvature="0"
style="fill:#bebebe;stroke:#8c8c8c;stroke-width:0.99999994" />
<path
d="m 13.5,3.5 h 3 v 3 h -3 z"
id="path14"
inkscape:connector-curvature="0"
style="fill:#bebebe;stroke:#8c8c8c;stroke-width:0.99999994" />
<path
d="m 19.5,3.5 h 3 v 3 h -3 z"
id="path16"
inkscape:connector-curvature="0"
style="fill:#bebebe;stroke:#8c8c8c;stroke-width:0.99999994" />
<rect
style="fill:#3c5a6e"
id="rect18"
y="13"
x="13"
width="11"
rx="2.0114901"
height="11" />
<path
style="opacity:0.3;fill:#fcffff;fill-rule:evenodd"
inkscape:connector-curvature="0"
id="path20"
d="M 14.000001,18.999999 23,18.9904 c 0,0 0,0 0,-2 C 23,14 22,14 18.5,14 15,14 14,14 14,17 c 0,2 0,2 10e-7,1.999999 z" />
<g
transform="translate(0.29660973,-0.33568939)"
id="g892">
<g
id="g863"
transform="translate(0.29652254,-0.63559322)">
<path
sodipodi:nodetypes="ccc"
d="m 21.73671,17.720509 c 0,-1.520773 -1.164073,-2.165959 -2.923152,-2.152625 -1.898205,-0.01537 -2.770607,0.433996 -2.770607,2.186312"
id="path14-3"
inkscape:connector-curvature="0"
style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:square" />
<path
d="m 18.085585,17.851653 -2,1.5 -2,-1.5"
id="path16-7"
inkscape:connector-curvature="0"
style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round" />
</g>
<g
transform="rotate(-180,18.055129,19.153486)"
id="g863-8">
<path
sodipodi:nodetypes="ccc"
d="m 21.73671,17.720509 c 0,-1.520773 -1.164073,-2.165959 -2.923152,-2.152625 -1.898205,-0.01537 -2.770607,0.433996 -2.770607,2.186312"
id="path14-3-5"
inkscape:connector-curvature="0"
style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:square" />
<path
d="m 18.085585,17.851653 -2,1.5 -2,-1.5"
id="path16-7-2"
inkscape:connector-curvature="0"
style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -98,6 +98,7 @@ SET(QGIS_APP_SRCS
qgsmaptooloffsetpointsymbol.cpp qgsmaptooloffsetpointsymbol.cpp
qgsmaptoolpointsymbol.cpp qgsmaptoolpointsymbol.cpp
qgsmaptoolreshape.cpp qgsmaptoolreshape.cpp
qgsmaptoolreverseline.cpp
qgsmaptoolrotatefeature.cpp qgsmaptoolrotatefeature.cpp
qgsmaptoolrotatelabel.cpp qgsmaptoolrotatelabel.cpp
qgsmaptoolrotatepointsymbols.cpp qgsmaptoolrotatepointsymbols.cpp
@ -320,6 +321,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmaptooloffsetpointsymbol.h qgsmaptooloffsetpointsymbol.h
qgsmaptoolpointsymbol.h qgsmaptoolpointsymbol.h
qgsmaptoolreshape.h qgsmaptoolreshape.h
qgsmaptoolreverseline.h
qgsmaptoolrotatefeature.h qgsmaptoolrotatefeature.h
qgsmaptoolrotatelabel.h qgsmaptoolrotatelabel.h
qgsmaptoolrotatepointsymbols.h qgsmaptoolrotatepointsymbols.h

View File

@ -403,6 +403,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgsmaptoolmovelabel.h" #include "qgsmaptoolmovelabel.h"
#include "qgsmaptoolrotatelabel.h" #include "qgsmaptoolrotatelabel.h"
#include "qgsmaptoolchangelabelproperties.h" #include "qgsmaptoolchangelabelproperties.h"
#include "qgsmaptoolreverseline.h"
#include "vertextool/qgsvertextool.h" #include "vertextool/qgsvertextool.h"
@ -1466,6 +1467,7 @@ QgisApp::~QgisApp()
delete mMapTools.mOffsetCurve; delete mMapTools.mOffsetCurve;
delete mMapTools.mPinLabels; delete mMapTools.mPinLabels;
delete mMapTools.mReshapeFeatures; delete mMapTools.mReshapeFeatures;
delete mMapTools.mReverseLine;
delete mMapTools.mRotateFeature; delete mMapTools.mRotateFeature;
delete mMapTools.mRotateLabel; delete mMapTools.mRotateLabel;
delete mMapTools.mRotatePointSymbolsTool; delete mMapTools.mRotatePointSymbolsTool;
@ -2063,6 +2065,7 @@ void QgisApp::createActions()
connect( mActionOffsetPointSymbol, &QAction::triggered, this, &QgisApp::offsetPointSymbol ); connect( mActionOffsetPointSymbol, &QAction::triggered, this, &QgisApp::offsetPointSymbol );
connect( mActionSnappingOptions, &QAction::triggered, this, &QgisApp::snappingOptions ); connect( mActionSnappingOptions, &QAction::triggered, this, &QgisApp::snappingOptions );
connect( mActionOffsetCurve, &QAction::triggered, this, &QgisApp::offsetCurve ); connect( mActionOffsetCurve, &QAction::triggered, this, &QgisApp::offsetCurve );
connect( mActionReverseLine, &QAction::triggered, this, &QgisApp::reverseLine );
// View Menu Items // View Menu Items
connect( mActionPan, &QAction::triggered, this, &QgisApp::pan ); connect( mActionPan, &QAction::triggered, this, &QgisApp::pan );
@ -2354,6 +2357,7 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionMoveLabel ); mMapToolGroup->addAction( mActionMoveLabel );
mMapToolGroup->addAction( mActionRotateLabel ); mMapToolGroup->addAction( mActionRotateLabel );
mMapToolGroup->addAction( mActionChangeLabelProperties ); mMapToolGroup->addAction( mActionChangeLabelProperties );
mMapToolGroup->addAction( mActionReverseLine );
// //
// Preview Modes Group // Preview Modes Group
@ -3307,6 +3311,7 @@ void QgisApp::setTheme( const QString &themeName )
mActionDecorationNorthArrow->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/north_arrow.png" ) ) ); mActionDecorationNorthArrow->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/north_arrow.png" ) ) );
mActionDecorationScaleBar->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionScaleBar.svg" ) ) ); mActionDecorationScaleBar->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionScaleBar.svg" ) ) );
mActionDecorationGrid->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) ) ); mActionDecorationGrid->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) ) );
mActionReverseLine->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionReverseLine.svg" ) ) );
emit currentThemeChanged( themeName ); emit currentThemeChanged( themeName );
} }
@ -3518,6 +3523,8 @@ void QgisApp::createCanvasTools()
mMapTools.mOffsetCurve->setAction( mActionOffsetCurve ); mMapTools.mOffsetCurve->setAction( mActionOffsetCurve );
mMapTools.mReshapeFeatures = new QgsMapToolReshape( mMapCanvas ); mMapTools.mReshapeFeatures = new QgsMapToolReshape( mMapCanvas );
mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures ); mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures );
mMapTools.mReverseLine = new QgsMapToolReverseLine( mMapCanvas );
mMapTools.mReverseLine->setAction( mActionReverseLine );
mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures( mMapCanvas ); mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures( mMapCanvas );
mMapTools.mSplitFeatures->setAction( mActionSplitFeatures ); mMapTools.mSplitFeatures->setAction( mActionSplitFeatures );
mMapTools.mSplitParts = new QgsMapToolSplitParts( mMapCanvas ); mMapTools.mSplitParts = new QgsMapToolSplitParts( mMapCanvas );
@ -7605,6 +7612,11 @@ void QgisApp::deletePart()
mMapCanvas->setMapTool( mMapTools.mDeletePart ); mMapCanvas->setMapTool( mMapTools.mDeletePart );
} }
void QgisApp::reverseLine()
{
mMapCanvas->setMapTool( mMapTools.mReverseLine );
}
QgsGeometry QgisApp::unionGeometries( const QgsVectorLayer *vl, QgsFeatureList &featureList, bool &canceled ) QgsGeometry QgisApp::unionGeometries( const QgsVectorLayer *vl, QgsFeatureList &featureList, bool &canceled )
{ {
canceled = false; canceled = false;
@ -12140,6 +12152,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
mActionPasteStyle->setEnabled( false ); mActionPasteStyle->setEnabled( false );
mActionCopyLayer->setEnabled( false ); mActionCopyLayer->setEnabled( false );
mActionPasteLayer->setEnabled( false ); mActionPasteLayer->setEnabled( false );
mActionReverseLine->setEnabled( false );
mUndoDock->widget()->setEnabled( false ); mUndoDock->widget()->setEnabled( false );
mActionUndo->setEnabled( false ); mActionUndo->setEnabled( false );
@ -12214,6 +12227,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
mActionZoomToSelected->setEnabled( isSpatial ); mActionZoomToSelected->setEnabled( isSpatial );
mActionLabeling->setEnabled( isSpatial ); mActionLabeling->setEnabled( isSpatial );
mActionDiagramProperties->setEnabled( isSpatial ); mActionDiagramProperties->setEnabled( isSpatial );
mActionReverseLine->setEnabled( false );
mActionSelectFeatures->setEnabled( isSpatial ); mActionSelectFeatures->setEnabled( isSpatial );
mActionSelectPolygon->setEnabled( isSpatial ); mActionSelectPolygon->setEnabled( isSpatial );
@ -12357,6 +12371,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
mActionSplitParts->setEnabled( isEditable && canChangeGeometry && isMultiPart ); mActionSplitParts->setEnabled( isEditable && canChangeGeometry && isMultiPart );
mActionSimplifyFeature->setEnabled( isEditable && canChangeGeometry ); mActionSimplifyFeature->setEnabled( isEditable && canChangeGeometry );
mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes ); mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes );
mActionReverseLine->setEnabled( isEditable && canChangeGeometry );
mActionAddRing->setEnabled( false ); mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false ); mActionFillRing->setEnabled( false );

View File

@ -1399,6 +1399,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void rotatePointSymbols(); void rotatePointSymbols();
//! activates the offset point symbol tool //! activates the offset point symbol tool
void offsetPointSymbol(); void offsetPointSymbol();
//! activates the reverse line tool
void reverseLine();
//! activates the tool //! activates the tool
void setMapTool( QgsMapTool *tool, bool clean = false ); void setMapTool( QgsMapTool *tool, bool clean = false );
@ -2056,6 +2058,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMapTool *mRotateFeature = nullptr; QgsMapTool *mRotateFeature = nullptr;
QgsMapTool *mRotateLabel = nullptr; QgsMapTool *mRotateLabel = nullptr;
QgsMapTool *mChangeLabelProperties = nullptr; QgsMapTool *mChangeLabelProperties = nullptr;
QgsMapTool *mReverseLine = nullptr ;
} mMapTools; } mMapTools;
QgsMapTool *mNonEditMapTool = nullptr; QgsMapTool *mNonEditMapTool = nullptr;

View File

@ -0,0 +1,182 @@
/***************************************************************************
qgsmaptoolreverseline.cpp - reverse a line geometry
---------------------
begin : April 2018
copyright : (C) 2018 by Loïc Bartoletti
email : loic dot bartoletti at oslandia dot com
***************************************************************************
* *
* 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 "qgsmaptoolreverseline.h"
#include "qgsfeatureiterator.h"
#include "qgsmapcanvas.h"
#include "qgsvertexmarker.h"
#include "qgsvectorlayer.h"
#include "qgsgeometry.h"
#include "qgsrubberband.h"
#include "qgssnappingutils.h"
#include "qgstolerance.h"
#include "qgisapp.h"
#include "qgslinestring.h"
#include "qgsmultilinestring.h"
#include <QMouseEvent>
QgsMapToolReverseLine::QgsMapToolReverseLine( QgsMapCanvas *canvas )
: QgsMapToolEdit( canvas )
{
mToolName = tr( "Reverse line geometry" );
}
QgsMapToolReverseLine::~QgsMapToolReverseLine()
{
}
void QgsMapToolReverseLine::canvasMoveEvent( QgsMapMouseEvent *e )
{
Q_UNUSED( e );
//nothing to do
}
void QgsMapToolReverseLine::canvasPressEvent( QgsMapMouseEvent *e )
{
mPressedFid = -1;
mPressedPartNum = -1;
QgsMapLayer *currentLayer = mCanvas->currentLayer();
if ( !currentLayer )
return;
vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
if ( !vlayer )
{
notifyNotVectorLayer();
return;
}
if ( !vlayer->isEditable() )
{
notifyNotEditableLayer();
return;
}
QgsGeometry geomPart = partUnderPoint( e->pos(), mPressedFid, mPressedPartNum );
if ( mPressedFid != -1 )
{
mRubberBand.reset( createRubberBand( vlayer->geometryType() ) );
mRubberBand->setToGeometry( geomPart, vlayer );
mRubberBand->show();
}
}
void QgsMapToolReverseLine::canvasReleaseEvent( QgsMapMouseEvent *e )
{
Q_UNUSED( e );
if ( !vlayer || !vlayer->isEditable() )
{
return;
}
if ( mPressedFid == -1 )
return;
QgsFeature f;
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( mPressedFid ) ).nextFeature( f );
QgsGeometry geom;
if ( f.hasGeometry() )
{
if ( f.geometry().isMultipart() )
{
std::unique_ptr<QgsMultiCurve> line_reversed( static_cast<QgsMultiCurve * >( f.geometry().constGet()->clone() ) );
std::unique_ptr<QgsCurve> line_part( static_cast<QgsCurve *>( line_reversed->geometryN( mPressedPartNum )->clone() ) );
std::unique_ptr<QgsCurve> line_part_reversed( line_part->reversed() );
line_reversed->removeGeometry( mPressedPartNum );
line_reversed->insertGeometry( line_part_reversed.release(), mPressedPartNum );
geom = QgsGeometry( line_reversed.release() );
}
else
{
geom = QgsGeometry( static_cast< const QgsCurve * >( f.geometry().constGet() )->reversed() );
}
if ( geom )
{
vlayer->beginEditCommand( tr( "Reverse line" ) );
vlayer->changeGeometry( f.id(), geom );
vlayer->endEditCommand();
vlayer->triggerRepaint();
emit messageEmitted( tr( "Line reversed." ) );
}
else
{
emit messageEmitted( tr( "Couldn't reverse the selected part." ) );
}
}
}
QgsGeometry QgsMapToolReverseLine::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum )
{
QgsFeature f;
QgsGeometry geomPart;
switch ( vlayer->geometryType() )
{
case QgsWkbTypes::LineGeometry:
{
QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) );
if ( !match.isValid() )
return geomPart;
int snapVertex = match.vertexIndex();
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f );
QgsGeometry g = f.geometry();
if ( !g.isMultipart() )
{
fid = match.featureId();
return g;
}
else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::LineGeometry )
{
QgsMultiPolylineXY mline = g.asMultiPolyline();
for ( int part = 0; part < mline.count(); part++ )
{
if ( snapVertex < mline[part].count() )
{
fid = match.featureId();
partNum = part;
return QgsGeometry::fromPolylineXY( mline[part] );
}
snapVertex -= mline[part].count();
}
}
break;
}
default:
{
break;
}
}
return geomPart;
}
void QgsMapToolReverseLine::deactivate()
{
QgsMapTool::deactivate();
}

View File

@ -0,0 +1,56 @@
/***************************************************************************
qgsmaptoolreverseline.h - reverse a line geometry
---------------------
begin : April 2018
copyright : (C) 2018 by Loïc Bartoletti
email : loic dot bartoletti at oslandia dot com
***************************************************************************
* *
* 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 QGSMAPTOOLREVERSELINE_H
#define QGSMAPTOOLREVERSELINE_H
#include "qgsmaptooledit.h"
#include "qgis_app.h"
class QgsVertexMarker;
//! Map tool to delete vertices from line/polygon features
class APP_EXPORT QgsMapToolReverseLine: public QgsMapToolEdit
{
Q_OBJECT
public:
QgsMapToolReverseLine( QgsMapCanvas *canvas );
~QgsMapToolReverseLine() override;
void canvasMoveEvent( QgsMapMouseEvent *e ) override;
void canvasPressEvent( QgsMapMouseEvent *e ) override;
void canvasReleaseEvent( QgsMapMouseEvent *e ) override;
//! called when map tool is being deactivated
void deactivate() override;
private:
QgsVectorLayer *vlayer = nullptr;
QgsGeometry partUnderPoint( QPoint p, QgsFeatureId &fid, int &partNum );
/* Rubberband that shows the part being reversed*/
std::unique_ptr<QgsRubberBand>mRubberBand;
//The feature and part where the mouse cursor was pressed
//This is used to check whether we are still in the same part at cursor release
QgsFeatureId mPressedFid = 0;
int mPressedPartNum = 0;
};
#endif // QGSMAPTOOLREVERSELINE_H

View File

@ -362,6 +362,7 @@
<addaction name="mActionVertexTool"/> <addaction name="mActionVertexTool"/>
<addaction name="mActionRotatePointSymbols"/> <addaction name="mActionRotatePointSymbols"/>
<addaction name="mActionOffsetPointSymbol"/> <addaction name="mActionOffsetPointSymbol"/>
<addaction name="mActionReverseLine"/>
</widget> </widget>
<addaction name="mProjectMenu"/> <addaction name="mProjectMenu"/>
<addaction name="mEditMenu"/> <addaction name="mEditMenu"/>
@ -468,6 +469,7 @@
<addaction name="mActionDeletePart"/> <addaction name="mActionDeletePart"/>
<addaction name="mActionReshapeFeatures"/> <addaction name="mActionReshapeFeatures"/>
<addaction name="mActionOffsetCurve"/> <addaction name="mActionOffsetCurve"/>
<addaction name="mActionReverseLine"/>
<addaction name="mActionSplitFeatures"/> <addaction name="mActionSplitFeatures"/>
<addaction name="mActionSplitParts"/> <addaction name="mActionSplitParts"/>
<addaction name="mActionMergeFeatures"/> <addaction name="mActionMergeFeatures"/>
@ -1047,6 +1049,18 @@
<string>Offset Point Symbol</string> <string>Offset Point Symbol</string>
</property> </property>
</action> </action>
<action name="mActionReverseLine">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionReverseLine.svg</normaloff>:/images/themes/default/mActionReverseLine.svg</iconset>
</property>
<property name="text">
<string>Reverse line</string>
</property>
</action>
<action name="mActionSnappingOptions"> <action name="mActionSnappingOptions">
<property name="text"> <property name="text">
<string>&amp;Snapping Options…</string> <string>&amp;Snapping Options…</string>

View File

@ -108,3 +108,5 @@ ADD_QGIS_TEST(maptoolregularpolygontest testqgsmaptoolregularpolygon.cpp)
ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp) ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp)
ADD_QGIS_TEST(vertextool testqgsvertextool.cpp) ADD_QGIS_TEST(vertextool testqgsvertextool.cpp)
ADD_QGIS_TEST(vectorlayersaveasdialogtest testqgsvectorlayersaveasdialog.cpp) ADD_QGIS_TEST(vectorlayersaveasdialogtest testqgsvectorlayersaveasdialog.cpp)
ADD_QGIS_TEST(maptoolreverselinetest testqgsmaptoolreverseline.cpp)

View File

@ -0,0 +1,190 @@
/***************************************************************************
TestQgsMapToolReverseLine.cpp
--------------------------------
Date : May 2018
Copyright : (C) 2018 by Loïc Bartoletti
Email : loic dot bartoletti at oslandia dot com
***************************************************************************
* *
* 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 "qgstest.h"
#include "qgisapp.h"
#include "qgsgeometry.h"
#include "qgsmapcanvas.h"
#include "qgssettings.h"
#include "qgsvectorlayer.h"
#include "qgsmaptooladdfeature.h"
#include "testqgsmaptoolutils.h"
#include "qgsmaptoolreverseline.h"
class TestQgsMapToolReverseLine : public QObject
{
Q_OBJECT
public:
TestQgsMapToolReverseLine();
private slots:
void initTestCase();
void cleanupTestCase();
void testReverseCurve();
void testReverseLineString();
void testReverseMultiLineString();
private:
QgisApp *mQgisApp = nullptr;
QgsMapCanvas *mCanvas = nullptr;
};
TestQgsMapToolReverseLine::TestQgsMapToolReverseLine() = default;
//runs before all tests
void TestQgsMapToolReverseLine::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
mQgisApp = new QgisApp();
mCanvas = new QgsMapCanvas();
mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) );
}
void TestQgsMapToolReverseLine::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgsMapToolReverseLine::testReverseCurve()
{
//create a temporary layer
std::unique_ptr< QgsVectorLayer > memoryLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:3946&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QVERIFY( memoryLayer->isValid() );
QgsFeature curve( memoryLayer->dataProvider()->fields(), 1 );
curve.setAttribute( QStringLiteral( "pk" ), 1 );
curve.setGeometry( QgsGeometry::fromWkt( QStringLiteral(
"CircularString(10 10, 5 5)" ) ) );
memoryLayer->dataProvider()->addFeatures( QgsFeatureList() << curve );
mCanvas->setLayers( QList<QgsMapLayer *>() << memoryLayer.get() );
mCanvas->setCurrentLayer( memoryLayer.get() );
std::unique_ptr< QgsMapToolReverseLine > tool( new QgsMapToolReverseLine( mCanvas ) );
memoryLayer->startEditing();
QgsPointXY mapPoint = mCanvas->getCoordinateTransform()->transform( 5, 5 );
std::unique_ptr< QgsMapMouseEvent > event( new QgsMapMouseEvent(
mCanvas,
QEvent::MouseButtonRelease,
QPoint( mapPoint.x(), mapPoint.y() )
) );
// trigger mouseRelease handler
tool->canvasPressEvent( event.get() );
tool->canvasReleaseEvent( event.get() );
QgsFeature f = memoryLayer->getFeature( 1 );
QString wkt = "CircularString (5 5, 10 10)";
QCOMPARE( f.geometry().asWkt(), wkt );
memoryLayer->rollBack();
}
void TestQgsMapToolReverseLine::testReverseLineString()
{
//create a temporary layer
std::unique_ptr< QgsVectorLayer > memoryLayer( new QgsVectorLayer( QStringLiteral( "LineStringZ?crs=EPSG:3946&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QVERIFY( memoryLayer->isValid() );
QgsFeature line( memoryLayer->dataProvider()->fields(), 1 );
line.setAttribute( QStringLiteral( "pk" ), 1 );
line.setGeometry( QgsGeometry::fromWkt( QStringLiteral(
"LineStringZ(0 0 0, 10 10 10, 5 5 5)" ) ) );
memoryLayer->dataProvider()->addFeatures( QgsFeatureList() << line );
mCanvas->setLayers( QList<QgsMapLayer *>() << memoryLayer.get() );
mCanvas->setCurrentLayer( memoryLayer.get() );
std::unique_ptr< QgsMapToolReverseLine > tool( new QgsMapToolReverseLine( mCanvas ) );
memoryLayer->startEditing();
QgsPointXY mapPoint = mCanvas->getCoordinateTransform()->transform( 6, 6 );
std::unique_ptr< QgsMapMouseEvent > event( new QgsMapMouseEvent(
mCanvas,
QEvent::MouseButtonRelease,
QPoint( mapPoint.x(), mapPoint.y() )
) );
// trigger mouseRelease handler
tool->canvasPressEvent( event.get() );
tool->canvasReleaseEvent( event.get() );
QgsFeature f = memoryLayer->getFeature( 1 );
QString wkt = "LineStringZ (5 5 5, 10 10 10, 0 0 0)";
QCOMPARE( f.geometry().asWkt(), wkt );
memoryLayer->rollBack();
}
void TestQgsMapToolReverseLine::testReverseMultiLineString()
{
//create a temporary layer
std::unique_ptr< QgsVectorLayer > memoryLayer( new QgsVectorLayer( QStringLiteral( "MultiLineStringZ?crs=EPSG:3946&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QVERIFY( memoryLayer->isValid() );
QgsFeature multi( memoryLayer->dataProvider()->fields(), 1 );
multi.setAttribute( QStringLiteral( "pk" ), 1 );
multi.setGeometry( QgsGeometry::fromWkt( QStringLiteral(
"MultiLineStringZ((0 0 0, 10 10 10, 5 5 5), (100 100 100, 120 120 120))" ) ) );
memoryLayer->dataProvider()->addFeatures( QgsFeatureList() << multi );
mCanvas->setLayers( QList<QgsMapLayer *>() << memoryLayer.get() );
mCanvas->setCurrentLayer( memoryLayer.get() );
std::unique_ptr< QgsMapToolReverseLine > tool( new QgsMapToolReverseLine( mCanvas ) );
memoryLayer->startEditing();
QgsPointXY mapPoint = mCanvas->getCoordinateTransform()->transform( 6, 6 );
std::unique_ptr< QgsMapMouseEvent > event( new QgsMapMouseEvent(
mCanvas,
QEvent::MouseButtonRelease,
QPoint( mapPoint.x(), mapPoint.y() )
) );
// trigger mouseRelease handler
tool->canvasPressEvent( event.get() );
tool->canvasReleaseEvent( event.get() );
QgsFeature f = memoryLayer->getFeature( 1 );
QString wkt = "MultiLineStringZ ((5 5 5, 10 10 10, 0 0 0),(100 100 100, 120 120 120))";
QCOMPARE( f.geometry().asWkt(), wkt );
mapPoint = mCanvas->getCoordinateTransform()->transform( 110, 110 );
event.reset( new QgsMapMouseEvent(
mCanvas,
QEvent::MouseButtonRelease,
QPoint( mapPoint.x(), mapPoint.y() )
) );
// trigger mouseRelease handler
tool->canvasPressEvent( event.get() );
tool->canvasReleaseEvent( event.get() );
f = memoryLayer->getFeature( 1 );
wkt = "MultiLineStringZ ((5 5 5, 10 10 10, 0 0 0),(120 120 120, 100 100 100))";
QCOMPARE( f.geometry().asWkt(), wkt );
memoryLayer->rollBack();
}
QGSTEST_MAIN( TestQgsMapToolReverseLine )
#include "testqgsmaptoolreverseline.moc"