mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -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/mAddToProject.svg</file>
|
||||
<file>themes/default/mDockify.svg</file>
|
||||
<file>themes/default/mActionReverseLine.svg</file>
|
||||
<file>themes/default/mActionAdd3DMap.svg</file>
|
||||
</qresource>
|
||||
<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
|
||||
qgsmaptoolpointsymbol.cpp
|
||||
qgsmaptoolreshape.cpp
|
||||
qgsmaptoolreverseline.cpp
|
||||
qgsmaptoolrotatefeature.cpp
|
||||
qgsmaptoolrotatelabel.cpp
|
||||
qgsmaptoolrotatepointsymbols.cpp
|
||||
@ -320,6 +321,7 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgsmaptooloffsetpointsymbol.h
|
||||
qgsmaptoolpointsymbol.h
|
||||
qgsmaptoolreshape.h
|
||||
qgsmaptoolreverseline.h
|
||||
qgsmaptoolrotatefeature.h
|
||||
qgsmaptoolrotatelabel.h
|
||||
qgsmaptoolrotatepointsymbols.h
|
||||
|
@ -403,6 +403,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
|
||||
#include "qgsmaptoolmovelabel.h"
|
||||
#include "qgsmaptoolrotatelabel.h"
|
||||
#include "qgsmaptoolchangelabelproperties.h"
|
||||
#include "qgsmaptoolreverseline.h"
|
||||
|
||||
#include "vertextool/qgsvertextool.h"
|
||||
|
||||
@ -1466,6 +1467,7 @@ QgisApp::~QgisApp()
|
||||
delete mMapTools.mOffsetCurve;
|
||||
delete mMapTools.mPinLabels;
|
||||
delete mMapTools.mReshapeFeatures;
|
||||
delete mMapTools.mReverseLine;
|
||||
delete mMapTools.mRotateFeature;
|
||||
delete mMapTools.mRotateLabel;
|
||||
delete mMapTools.mRotatePointSymbolsTool;
|
||||
@ -2063,6 +2065,7 @@ void QgisApp::createActions()
|
||||
connect( mActionOffsetPointSymbol, &QAction::triggered, this, &QgisApp::offsetPointSymbol );
|
||||
connect( mActionSnappingOptions, &QAction::triggered, this, &QgisApp::snappingOptions );
|
||||
connect( mActionOffsetCurve, &QAction::triggered, this, &QgisApp::offsetCurve );
|
||||
connect( mActionReverseLine, &QAction::triggered, this, &QgisApp::reverseLine );
|
||||
|
||||
// View Menu Items
|
||||
connect( mActionPan, &QAction::triggered, this, &QgisApp::pan );
|
||||
@ -2354,6 +2357,7 @@ void QgisApp::createActionGroups()
|
||||
mMapToolGroup->addAction( mActionMoveLabel );
|
||||
mMapToolGroup->addAction( mActionRotateLabel );
|
||||
mMapToolGroup->addAction( mActionChangeLabelProperties );
|
||||
mMapToolGroup->addAction( mActionReverseLine );
|
||||
|
||||
//
|
||||
// Preview Modes Group
|
||||
@ -3307,6 +3311,7 @@ void QgisApp::setTheme( const QString &themeName )
|
||||
mActionDecorationNorthArrow->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/north_arrow.png" ) ) );
|
||||
mActionDecorationScaleBar->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionScaleBar.svg" ) ) );
|
||||
mActionDecorationGrid->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) ) );
|
||||
mActionReverseLine->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionReverseLine.svg" ) ) );
|
||||
|
||||
emit currentThemeChanged( themeName );
|
||||
}
|
||||
@ -3518,6 +3523,8 @@ void QgisApp::createCanvasTools()
|
||||
mMapTools.mOffsetCurve->setAction( mActionOffsetCurve );
|
||||
mMapTools.mReshapeFeatures = new QgsMapToolReshape( mMapCanvas );
|
||||
mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures );
|
||||
mMapTools.mReverseLine = new QgsMapToolReverseLine( mMapCanvas );
|
||||
mMapTools.mReverseLine->setAction( mActionReverseLine );
|
||||
mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures( mMapCanvas );
|
||||
mMapTools.mSplitFeatures->setAction( mActionSplitFeatures );
|
||||
mMapTools.mSplitParts = new QgsMapToolSplitParts( mMapCanvas );
|
||||
@ -7605,6 +7612,11 @@ void QgisApp::deletePart()
|
||||
mMapCanvas->setMapTool( mMapTools.mDeletePart );
|
||||
}
|
||||
|
||||
void QgisApp::reverseLine()
|
||||
{
|
||||
mMapCanvas->setMapTool( mMapTools.mReverseLine );
|
||||
}
|
||||
|
||||
QgsGeometry QgisApp::unionGeometries( const QgsVectorLayer *vl, QgsFeatureList &featureList, bool &canceled )
|
||||
{
|
||||
canceled = false;
|
||||
@ -12140,6 +12152,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
|
||||
mActionPasteStyle->setEnabled( false );
|
||||
mActionCopyLayer->setEnabled( false );
|
||||
mActionPasteLayer->setEnabled( false );
|
||||
mActionReverseLine->setEnabled( false );
|
||||
|
||||
mUndoDock->widget()->setEnabled( false );
|
||||
mActionUndo->setEnabled( false );
|
||||
@ -12214,6 +12227,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
|
||||
mActionZoomToSelected->setEnabled( isSpatial );
|
||||
mActionLabeling->setEnabled( isSpatial );
|
||||
mActionDiagramProperties->setEnabled( isSpatial );
|
||||
mActionReverseLine->setEnabled( false );
|
||||
|
||||
mActionSelectFeatures->setEnabled( isSpatial );
|
||||
mActionSelectPolygon->setEnabled( isSpatial );
|
||||
@ -12357,6 +12371,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
|
||||
mActionSplitParts->setEnabled( isEditable && canChangeGeometry && isMultiPart );
|
||||
mActionSimplifyFeature->setEnabled( isEditable && canChangeGeometry );
|
||||
mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes );
|
||||
mActionReverseLine->setEnabled( isEditable && canChangeGeometry );
|
||||
|
||||
mActionAddRing->setEnabled( false );
|
||||
mActionFillRing->setEnabled( false );
|
||||
|
@ -1399,6 +1399,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
void rotatePointSymbols();
|
||||
//! activates the offset point symbol tool
|
||||
void offsetPointSymbol();
|
||||
//! activates the reverse line tool
|
||||
void reverseLine();
|
||||
//! activates the tool
|
||||
void setMapTool( QgsMapTool *tool, bool clean = false );
|
||||
|
||||
@ -2056,6 +2058,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
QgsMapTool *mRotateFeature = nullptr;
|
||||
QgsMapTool *mRotateLabel = nullptr;
|
||||
QgsMapTool *mChangeLabelProperties = nullptr;
|
||||
QgsMapTool *mReverseLine = nullptr ;
|
||||
} mMapTools;
|
||||
|
||||
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="mActionRotatePointSymbols"/>
|
||||
<addaction name="mActionOffsetPointSymbol"/>
|
||||
<addaction name="mActionReverseLine"/>
|
||||
</widget>
|
||||
<addaction name="mProjectMenu"/>
|
||||
<addaction name="mEditMenu"/>
|
||||
@ -468,6 +469,7 @@
|
||||
<addaction name="mActionDeletePart"/>
|
||||
<addaction name="mActionReshapeFeatures"/>
|
||||
<addaction name="mActionOffsetCurve"/>
|
||||
<addaction name="mActionReverseLine"/>
|
||||
<addaction name="mActionSplitFeatures"/>
|
||||
<addaction name="mActionSplitParts"/>
|
||||
<addaction name="mActionMergeFeatures"/>
|
||||
@ -1047,6 +1049,18 @@
|
||||
<string>Offset Point Symbol</string>
|
||||
</property>
|
||||
</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">
|
||||
<property name="text">
|
||||
<string>&Snapping Options…</string>
|
||||
|
@ -108,3 +108,5 @@ ADD_QGIS_TEST(maptoolregularpolygontest testqgsmaptoolregularpolygon.cpp)
|
||||
ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp)
|
||||
ADD_QGIS_TEST(vertextool testqgsvertextool.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