Navigation Menu

Skip to content

Commit

Permalink
Merge pull request #35875 from olivierdalang/tracing_curves_prototype
Browse files Browse the repository at this point in the history
[feature] Curved geometries support for trace tool
  • Loading branch information
m-kuhn committed May 15, 2020
2 parents 4a78523 + 52fd8eb commit 0617e52
Show file tree
Hide file tree
Showing 25 changed files with 860 additions and 4 deletions.
19 changes: 19 additions & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1229,6 +1229,25 @@ Curved geometry types are automatically segmentized by this routine.
.. seealso:: :py:func:`densifyByCount`

.. versionadded:: 3.0
%End

QgsGeometry convertToCurves( double distanceTolerance = 1e-8, double angleTolerance = 1e-8 ) const;
%Docstring
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
LineString to CompoundCurve, Polygon to CurvePolygon).

The ``distanceTolerance`` specifies the maximum deviation allowed between the original location
of vertices and where they would fall on the candidate curved geometry.

This method only consider a segments as suitable for replacing with an arc if the points are all
regularly spaced on the candidate arc. The ``pointSpacingAngleTolerance`` parameter specifies the maximum
angular deviation (in radians) allowed when testing for regular point spacing.

.. note::

The API is considered EXPERIMENTAL and can be changed without a notice

.. versionadded:: 3.14
%End

QgsGeometry centroid() const;
Expand Down
22 changes: 21 additions & 1 deletion python/core/auto_generated/geometry/qgsgeometryutils.sip.in
Expand Up @@ -242,7 +242,7 @@ Project the point on a segment

static int leftOfLine( const double x, const double y, const double x1, const double y1, const double x2, const double y2 );
%Docstring
Returns a value < 0 if the point (``x``, ``y``) is left of the line from (``x1``, ``y1``) -> ( ``x2``, ``y2``).
Returns a value < 0 if the point (``x``, ``y``) is left of the line from (``x1``, ``y1``) -> (``x2``, ``y2``).
A positive return value indicates the point is to the right of the line.

If the return value is 0, then the test was unsuccessful (e.g. due to testing a point exactly
Expand Down Expand Up @@ -352,6 +352,26 @@ Calculates the direction angle of a circle tangent (clockwise from north in radi
Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp. end point, p2 lies on the arc) into a sequence of points.

.. versionadded:: 3.0
%End

static bool pointContinuesArc( const QgsPoint &a1, const QgsPoint &a2, const QgsPoint &a3, const QgsPoint &b, double distanceTolerance,
double pointSpacingAngleTolerance );
%Docstring
Returns true if point ``b`` is on the arc formed by points ``a1``, ``a2``, and ``a3``, but not within
that arc portion already described by ``a1``, ``a2`` and ``a3``.

The ``distanceTolerance`` specifies the maximum deviation allowed between the original location
of point \b and where it would fall on the candidate arc.

This method only consider a segments as continuing an arc if the points are all regularly spaced
on the candidate arc. The ``pointSpacingAngleTolerance`` parameter specifies the maximum
angular deviation (in radians) allowed when testing for regular point spacing.

.. note::

The API is considered EXPERIMENTAL and can be changed without a notice

.. versionadded:: 3.14
%End

static int segmentSide( const QgsPoint &pt1, const QgsPoint &pt3, const QgsPoint &pt2 );
Expand Down
17 changes: 17 additions & 0 deletions python/gui/auto_generated/qgsmaptoolcapture.sip.in
Expand Up @@ -27,13 +27,27 @@ class QgsMapToolCapture : QgsMapToolAdvancedDigitizing
CapturePolygon
};

enum Capability
{
NoCapabilities,
SupportsCurves,
};

typedef QFlags<QgsMapToolCapture::Capability> Capabilities;


QgsMapToolCapture( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode );
%Docstring
constructor
%End

~QgsMapToolCapture();

virtual QgsMapToolCapture::Capabilities capabilities() const;
%Docstring
Returns flags containing the supported capabilities
%End

virtual void activate();

virtual void deactivate();
Expand Down Expand Up @@ -266,6 +280,9 @@ Stop capturing

};

QFlags<QgsMapToolCapture::Capability> operator|(QgsMapToolCapture::Capability f1, QFlags<QgsMapToolCapture::Capability> f2);


/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
3 changes: 3 additions & 0 deletions python/gui/auto_generated/qgsmaptooldigitizefeature.sip.in
Expand Up @@ -32,6 +32,9 @@ QgsMapToolDigitizeFeature is a map tool to digitize a feature geometry
:param mode: type of geometry to capture (point/line/polygon), QgsMapToolCapture.CaptureNone to autodetect geometry
%End

virtual QgsMapToolCapture::Capabilities capabilities() const;


virtual void cadCanvasReleaseEvent( QgsMapMouseEvent *e );


Expand Down
1 change: 1 addition & 0 deletions src/analysis/CMakeLists.txt
Expand Up @@ -39,6 +39,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmclip.cpp
processing/qgsalgorithmconditionalbranch.cpp
processing/qgsalgorithmconstantraster.cpp
processing/qgsalgorithmconverttocurves.cpp
processing/qgsalgorithmconvexhull.cpp
processing/qgsalgorithmdbscanclustering.cpp
processing/qgsalgorithmdeleteduplicategeometries.cpp
Expand Down
157 changes: 157 additions & 0 deletions src/analysis/processing/qgsalgorithmconverttocurves.cpp
@@ -0,0 +1,157 @@
/***************************************************************************
qgsalgorithmconverttocurves.cpp
---------------------
begin : March 2018
copyright : (C) 2018 by Nyall Dawson
email : nyall dot dawson at gmail 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 "qgsalgorithmconverttocurves.h"

///@cond PRIVATE

QString QgsConvertToCurvesAlgorithm::name() const
{
return QStringLiteral( "converttocurves" );
}

QString QgsConvertToCurvesAlgorithm::displayName() const
{
return QObject::tr( "Convert to curved geometries" );
}

QStringList QgsConvertToCurvesAlgorithm::tags() const
{
return QObject::tr( "straight,segmentize,curves,curved,circular" ).split( ',' );
}

QString QgsConvertToCurvesAlgorithm::group() const
{
return QObject::tr( "Vector geometry" );
}

QString QgsConvertToCurvesAlgorithm::groupId() const
{
return QStringLiteral( "vectorgeometry" );
}

QString QgsConvertToCurvesAlgorithm::outputName() const
{
return QObject::tr( "Curves" );
}

QString QgsConvertToCurvesAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm converts a geometry into its curved geometry equivalent.\n\n"
"Already curved geometries will be retained without change." );
}

QgsConvertToCurvesAlgorithm *QgsConvertToCurvesAlgorithm::createInstance() const
{
return new QgsConvertToCurvesAlgorithm();
}

QList<int> QgsConvertToCurvesAlgorithm::inputLayerTypes() const
{
return QList<int>() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon;
}

void QgsConvertToCurvesAlgorithm::initParameters( const QVariantMap & )
{
std::unique_ptr< QgsProcessingParameterNumber > tolerance = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DISTANCE" ),
QObject::tr( "Maximum distance tolerance" ), QgsProcessingParameterNumber::Double,
0.000001, false, 0, 10000000.0 );
tolerance->setIsDynamic( true );
tolerance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Maximum distance tolerance" ), QgsPropertyDefinition::DoublePositive ) );
tolerance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( tolerance.release() );

std::unique_ptr< QgsProcessingParameterNumber > angleTolerance = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ANGLE" ),
QObject::tr( "Maximum angle tolerance" ), QgsProcessingParameterNumber::Double,
0.000001, false, 0, 45.0 );
angleTolerance->setIsDynamic( true );
angleTolerance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ANGLE" ), QObject::tr( "Maximum angle tolerance" ), QgsPropertyDefinition::DoublePositive ) );
angleTolerance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( angleTolerance.release() );
}

bool QgsConvertToCurvesAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mTolerance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
mDynamicTolerance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
if ( mDynamicTolerance )
mToleranceProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();

mAngleTolerance = parameterAsDouble( parameters, QStringLiteral( "ANGLE" ), context );
mDynamicAngleTolerance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ANGLE" ) );
if ( mDynamicAngleTolerance )
mAngleToleranceProperty = parameters.value( QStringLiteral( "ANGLE" ) ).value< QgsProperty >();

return true;
}

QgsFeatureList QgsConvertToCurvesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
{
QgsFeature f = feature;
if ( f.hasGeometry() )
{
QgsGeometry geometry = f.geometry();
double tolerance = mTolerance;
if ( mDynamicTolerance )
tolerance = mToleranceProperty.valueAsDouble( context.expressionContext(), tolerance );
double angleTolerance = mAngleTolerance;
if ( mDynamicAngleTolerance )
angleTolerance = mAngleToleranceProperty.valueAsDouble( context.expressionContext(), angleTolerance );

f.setGeometry( geometry.convertToCurves( tolerance, angleTolerance * M_PI / 180.0 ) );
}
return QgsFeatureList() << f;
}

QgsWkbTypes::Type QgsConvertToCurvesAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
{
if ( QgsWkbTypes::isCurvedType( inputWkbType ) )
return inputWkbType;

QgsWkbTypes::Type outType = QgsWkbTypes::Unknown;
switch ( QgsWkbTypes::geometryType( inputWkbType ) )
{
case QgsWkbTypes::PointGeometry:
case QgsWkbTypes::NullGeometry:
case QgsWkbTypes::UnknownGeometry:
return inputWkbType;

case QgsWkbTypes::LineGeometry:
outType = QgsWkbTypes::CompoundCurve;
break;

case QgsWkbTypes::PolygonGeometry:
outType = QgsWkbTypes::CurvePolygon;
break;
}

if ( QgsWkbTypes::isMultiType( inputWkbType ) )
outType = QgsWkbTypes::multiType( outType );

if ( QgsWkbTypes::hasZ( inputWkbType ) )
outType = QgsWkbTypes::addZ( outType );

if ( QgsWkbTypes::hasM( inputWkbType ) )
outType = QgsWkbTypes::addM( outType );

return outType;
}


///@endcond


70 changes: 70 additions & 0 deletions src/analysis/processing/qgsalgorithmconverttocurves.h
@@ -0,0 +1,70 @@
/***************************************************************************
qgsalgorithmconverttocurves.h
---------------------
begin : March 2018
copyright : (C) 2018 by Nyall Dawson
email : nyall dot dawson at gmail 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 QGSALGORITHMCONVERTTOCURVES_H
#define QGSALGORITHMCONVERTTOCURVES_H

#define SIP_NO_FILE

#include "qgis.h"
#include "qgsprocessingalgorithm.h"
#include "qgsmaptopixelgeometrysimplifier.h"

///@cond PRIVATE

/**
* Native segmentize by maximum distance algorithm.
*/
class QgsConvertToCurvesAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{

public:

QgsConvertToCurvesAlgorithm() = default;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsConvertToCurvesAlgorithm *createInstance() const override SIP_FACTORY;
QList<int> inputLayerTypes() const override;
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;

protected:
QString outputName() const override;
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback ) override;
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override;

private:

double mTolerance = 0.000001;
bool mDynamicTolerance = false;
QgsProperty mToleranceProperty;

double mAngleTolerance = 0.000001;
bool mDynamicAngleTolerance = false;
QgsProperty mAngleToleranceProperty;

};

///@endcond PRIVATE

#endif // QGSALGORITHMCONVERTTOCURVES_H


2 changes: 2 additions & 0 deletions src/analysis/processing/qgsnativealgorithms.cpp
Expand Up @@ -34,6 +34,7 @@
#include "qgsalgorithmclip.h"
#include "qgsalgorithmconditionalbranch.h"
#include "qgsalgorithmconstantraster.h"
#include "qgsalgorithmconverttocurves.h"
#include "qgsalgorithmconvexhull.h"
#include "qgsalgorithmdbscanclustering.h"
#include "qgsalgorithmdeleteduplicategeometries.h"
Expand Down Expand Up @@ -232,6 +233,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsCombineStylesAlgorithm() );
addAlgorithm( new QgsConditionalBranchAlgorithm() );
addAlgorithm( new QgsConstantRasterAlgorithm() );
addAlgorithm( new QgsConvertToCurvesAlgorithm() );
addAlgorithm( new QgsConvexHullAlgorithm() );
addAlgorithm( new QgsDbscanClusteringAlgorithm() );
addAlgorithm( new QgsDeleteDuplicateGeometriesAlgorithm() );
Expand Down
5 changes: 5 additions & 0 deletions src/app/qgsmaptooladdpart.cpp
Expand Up @@ -35,6 +35,11 @@ QgsMapToolAddPart::QgsMapToolAddPart( QgsMapCanvas *canvas )
connect( QgisApp::instance(), &QgisApp::projectRead, this, &QgsMapToolAddPart::stopCapturing );
}

QgsMapToolCapture::Capabilities QgsMapToolAddPart::capabilities() const
{
return QgsMapToolCapture::SupportsCurves;
}

void QgsMapToolAddPart::canvasReleaseEvent( QgsMapMouseEvent *e )
{
if ( checkSelection() )
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsmaptooladdpart.h
Expand Up @@ -23,6 +23,8 @@ class APP_EXPORT QgsMapToolAddPart : public QgsMapToolCapture
public:
QgsMapToolAddPart( QgsMapCanvas *canvas );

QgsMapToolCapture::Capabilities capabilities() const override;

void canvasReleaseEvent( QgsMapMouseEvent *e ) override;
void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override;

Expand Down

0 comments on commit 0617e52

Please sign in to comment.