mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #5600 from Gustry/sortby
add order by expression algorithm
This commit is contained in:
commit
6b23e1f299
@ -25,7 +25,7 @@ How To
|
||||
To add a new test please follow these steps:
|
||||
|
||||
1. **Run the algorithm** you want to test in QGIS from the processing toolbox. If the
|
||||
result is a vector layer prefer GML as output for its support of mixed
|
||||
result is a vector layer prefer GML, with its XSD, as output for its support of mixed
|
||||
geometry types and good readability. Redirect output to
|
||||
`python/plugins/processing/tests/testdata/expected`. For input layers prefer to use what's already there in the folder `testdata`. If you need extra data, put it into `testdata/custom`.
|
||||
|
||||
@ -131,6 +131,8 @@ It couldn't be more trivial
|
||||
type: vector
|
||||
```
|
||||
|
||||
Add the expected GML and XSD in the folder.
|
||||
|
||||
#### Vector with tolerance
|
||||
|
||||
Sometimes different platforms create slightly different results which are
|
||||
@ -191,3 +193,10 @@ OUTPUT:
|
||||
- 'Geometry: Line String'
|
||||
- 'Feature Count: 6'
|
||||
```
|
||||
|
||||
Running tests locally
|
||||
------------------
|
||||
```bash
|
||||
ctest -V -R ProcessingQgisAlgorithmsTest
|
||||
```
|
||||
or one of the following value listed in the [CMakelists.txt](https://github.com/qgis/QGIS/blob/master/python/plugins/processing/tests/CMakeLists.txt)
|
||||
|
61
python/plugins/processing/tests/testdata/expected/order_by_expression.gml
vendored
Normal file
61
python/plugins/processing/tests/testdata/expected/order_by_expression.gml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ order_by_expression.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.1">
|
||||
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
|
||||
<ogr:name>Aaaaa</ogr:name>
|
||||
<ogr:intval>-33</ogr:intval>
|
||||
<ogr:floatval>0</ogr:floatval>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.3">
|
||||
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
|
||||
<ogr:name>ASDF</ogr:name>
|
||||
<ogr:intval>0</ogr:intval>
|
||||
<ogr:floatval xsi:nil="true"/>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.5">
|
||||
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
|
||||
<ogr:name>elim</ogr:name>
|
||||
<ogr:intval>2</ogr:intval>
|
||||
<ogr:floatval>3.33</ogr:floatval>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.0">
|
||||
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
|
||||
<ogr:name>aaaaa</ogr:name>
|
||||
<ogr:intval>33</ogr:intval>
|
||||
<ogr:floatval>44.123456</ogr:floatval>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.4">
|
||||
<ogr:name xsi:nil="true"/>
|
||||
<ogr:intval>120</ogr:intval>
|
||||
<ogr:floatval>-100291.43213</ogr:floatval>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:order_by_expression fid="polys.2">
|
||||
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,6 3,6 3,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
|
||||
<ogr:name>bbaaa</ogr:name>
|
||||
<ogr:intval xsi:nil="true"/>
|
||||
<ogr:floatval>0.123</ogr:floatval>
|
||||
</ogr:order_by_expression>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
43
python/plugins/processing/tests/testdata/expected/order_by_expression.xsd
vendored
Normal file
43
python/plugins/processing/tests/testdata/expected/order_by_expression.xsd
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="order_by_expression" type="ogr:order_by_expression_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="order_by_expression_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="5"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="intval" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:totalDigits value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="floatval" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
@ -3411,6 +3411,24 @@ tests:
|
||||
name: expected/add_field.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:orderbyexpression
|
||||
name: Order by expression
|
||||
params:
|
||||
ASCENDING: true
|
||||
EXPRESSION: intval
|
||||
INPUT:
|
||||
name: polys.gml
|
||||
type: vector
|
||||
NULLS_FIRST: false
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/order_by_expression.gml
|
||||
type: vector
|
||||
compare:
|
||||
fields:
|
||||
__all__:
|
||||
precision: 4
|
||||
|
||||
- algorithm: qgis:randompointsinextent
|
||||
name: Random point in extent, don't check result
|
||||
params:
|
||||
|
@ -46,6 +46,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmmergelines.cpp
|
||||
processing/qgsalgorithmminimumenclosingcircle.cpp
|
||||
processing/qgsalgorithmmultiparttosinglepart.cpp
|
||||
processing/qgsalgorithmorderbyexpression.cpp
|
||||
processing/qgsalgorithmorientedminimumboundingbox.cpp
|
||||
processing/qgsalgorithmpackage.cpp
|
||||
processing/qgsalgorithmpromotetomultipart.cpp
|
||||
|
106
src/analysis/processing/qgsalgorithmorderbyexpression.cpp
Normal file
106
src/analysis/processing/qgsalgorithmorderbyexpression.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmorderbyexpression.h
|
||||
---------------------
|
||||
begin : November 2017
|
||||
copyright : (C) 2017 by Etienne Trimaille
|
||||
email : etienne dot trimaille 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 "qgsalgorithmorderbyexpression.h"
|
||||
#include "qgsfeaturerequest.h"
|
||||
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsOrderByExpressionAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "orderbyexpression" );
|
||||
}
|
||||
|
||||
QString QgsOrderByExpressionAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Order by expression" );
|
||||
}
|
||||
|
||||
QStringList QgsOrderByExpressionAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "orderby,sort,expression,field" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsOrderByExpressionAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector general" );
|
||||
}
|
||||
|
||||
void QgsOrderByExpressionAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
|
||||
addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "INPUT" ) ) );
|
||||
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "ASCENDING" ), QObject::tr( "Ascending" ), true ) );
|
||||
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "NULLS_FIRST" ), QObject::tr( "Nulls first" ), false ) );
|
||||
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output layer" ) ) );
|
||||
}
|
||||
|
||||
QString QgsOrderByExpressionAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm sorts a vector layer according to an expression. Be careful, it might not work as expected with some providers, the order might not be kept every time." );
|
||||
}
|
||||
|
||||
QgsOrderByExpressionAlgorithm *QgsOrderByExpressionAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsOrderByExpressionAlgorithm();
|
||||
}
|
||||
|
||||
QVariantMap QgsOrderByExpressionAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
|
||||
QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
|
||||
|
||||
bool ascending = parameterAsBool( parameters, QStringLiteral( "ASCENDING" ), context );
|
||||
bool nullsFirst = parameterAsBool( parameters, QStringLiteral( "NULLS_FIRST" ), context );
|
||||
|
||||
QString sinkId;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, sinkId, source->fields(), source->wkbType(), source->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
QgsFeatureRequest request;
|
||||
request.addOrderBy( expressionString, ascending, nullsFirst );
|
||||
|
||||
QgsFeature inFeature;
|
||||
QgsFeatureIterator features = source->getFeatures( request );
|
||||
while ( features.nextFeature( inFeature ) )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
sink->addFeature( inFeature );
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), sinkId );
|
||||
return outputs;
|
||||
}
|
||||
|
||||
///@endcond
|
53
src/analysis/processing/qgsalgorithmorderbyexpression.h
Normal file
53
src/analysis/processing/qgsalgorithmorderbyexpression.h
Normal file
@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmorderbyexpression.h
|
||||
---------------------
|
||||
begin : November 2017
|
||||
copyright : (C) 2017 by Etienne Trimaille
|
||||
email : etienne dot trimaille 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 QGSALGORITHMORDERBYEXPRESSION_H
|
||||
#define QGSALGORITHMORDERBYEXPRESSION_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native order by expression algorithm.
|
||||
*/
|
||||
class QgsOrderByExpressionAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
public:
|
||||
QgsOrderByExpressionAlgorithm() = default;
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
virtual QStringList tags() const override;
|
||||
QString group() const override;
|
||||
QString shortHelpString() const override;
|
||||
QgsOrderByExpressionAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMORDERBYEXPRESSION_H
|
@ -43,6 +43,7 @@
|
||||
#include "qgsalgorithmmergelines.h"
|
||||
#include "qgsalgorithmminimumenclosingcircle.h"
|
||||
#include "qgsalgorithmmultiparttosinglepart.h"
|
||||
#include "qgsalgorithmorderbyexpression.h"
|
||||
#include "qgsalgorithmorientedminimumboundingbox.h"
|
||||
#include "qgsalgorithmpackage.h"
|
||||
#include "qgsalgorithmpromotetomultipart.h"
|
||||
@ -122,6 +123,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsMergeLinesAlgorithm() );
|
||||
addAlgorithm( new QgsMinimumEnclosingCircleAlgorithm() );
|
||||
addAlgorithm( new QgsMultipartToSinglepartAlgorithm() );
|
||||
addAlgorithm( new QgsOrderByExpressionAlgorithm() );
|
||||
addAlgorithm( new QgsOrientedMinimumBoundingBoxAlgorithm() );
|
||||
addAlgorithm( new QgsPackageAlgorithm() );
|
||||
addAlgorithm( new QgsPromoteToMultipartAlgorithm() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user