mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
Merge pull request #7659 from lbartoletti/reverseLine
[needs-docs][FEATURE] Add reverse line maptools AKA swap direction
This commit is contained in:
commit
e10d16e1da
@ -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">
|
||||||
|
142
images/themes/default/mActionReverseLine.svg
Normal file
142
images/themes/default/mActionReverseLine.svg
Normal 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 |
@ -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
|
||||||
|
@ -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 );
|
||||||
|
@ -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;
|
||||||
|
182
src/app/qgsmaptoolreverseline.cpp
Normal file
182
src/app/qgsmaptoolreverseline.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
56
src/app/qgsmaptoolreverseline.h
Normal file
56
src/app/qgsmaptoolreverseline.h
Normal 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
|
@ -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>&Snapping Options…</string>
|
<string>&Snapping Options…</string>
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
190
tests/src/app/testqgsmaptoolreverseline.cpp
Normal file
190
tests/src/app/testqgsmaptoolreverseline.cpp
Normal 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"
|
Loading…
x
Reference in New Issue
Block a user