[FEATURE] Port autoincremental field to c++

Also add:
- support for setting initial value for field to start at
- support for user-set field names (instead of always using 'AUTO')
This commit is contained in:
Nyall Dawson 2017-10-12 08:29:25 +10:00
parent 61dc8ea28f
commit 97c1b0d322
10 changed files with 367 additions and 70 deletions

View File

@ -1,10 +1,3 @@
qgis:addautoincrementalfield: >
This algorithm adds a new integer field to a vector layer, with a sequential value for each feature.
This field can be used as a unique ID for features in the layer.
The new attribute is not added to the input layer but a new layer is generated instead.
qgis:addfieldtoattributestable: >
This algorithm adds a new attribute to a vector layer.

View File

@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
AutoincrementalField.py
---------------------
Date : August 2012
Copyright : (C) 2012 by Victor Olaya
Email : volayaf 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. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsField)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
class AutoincrementalField(QgisFeatureBasedAlgorithm):
def __init__(self):
super().__init__()
self.current = 0
def group(self):
return self.tr('Vector table')
def name(self):
return 'addautoincrementalfield'
def displayName(self):
return self.tr('Add autoincremental field')
def outputName(self):
return self.tr('Incremented')
def outputFields(self, inputFields):
inputFields.append(QgsField('AUTO', QVariant.Int))
return inputFields
def processFeature(self, feature, feedback):
attributes = feature.attributes()
attributes.append(self.current)
self.current += 1
feature.setAttributes(attributes)
return feature

View File

@ -43,7 +43,6 @@ from .QgisAlgorithm import QgisAlgorithm
from .AddTableField import AddTableField
from .Aggregate import Aggregate
from .Aspect import Aspect
from .AutoincrementalField import AutoincrementalField
from .BasicStatistics import BasicStatisticsForField
from .Boundary import Boundary
from .CheckValidity import CheckValidity
@ -174,7 +173,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
algs = [AddTableField(),
Aggregate(),
Aspect(),
AutoincrementalField(),
BasicStatisticsForField(),
Boundary(),
CheckValidity(),

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ autoincrement_field_field_name.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
<gml:coord><gml:X>8</gml:X><gml:Y>3</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.0">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>1</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:my_field>0</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.1">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>2</ogr:id>
<ogr:id2>1</ogr:id2>
<ogr:my_field>1</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.2">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>3</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:my_field>2</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.3">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>4</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:my_field>3</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.4">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>5</ogr:id>
<ogr:id2>1</ogr:id2>
<ogr:my_field>4</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.5">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>6</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:my_field>5</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.6">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>7</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:my_field>6</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.7">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>8</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:my_field>7</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_field_name fid="points.8">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>9</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:my_field>8</ogr:my_field>
</ogr:autoincrement_field_field_name>
</gml:featureMember>
</ogr:FeatureCollection>

View File

@ -0,0 +1,44 @@
<?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="autoincrement_field_field_name" type="ogr:autoincrement_field_field_name_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="autoincrement_field_field_name_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="id" 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="id2" 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="my_field" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ autoincrement_field_start.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
<gml:coord><gml:X>8</gml:X><gml:Y>3</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.0">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>1</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:AUTO>10</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.1">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>2</ogr:id>
<ogr:id2>1</ogr:id2>
<ogr:AUTO>11</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.2">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>3</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:AUTO>12</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.3">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>4</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:AUTO>13</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.4">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>5</ogr:id>
<ogr:id2>1</ogr:id2>
<ogr:AUTO>14</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.5">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>6</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:AUTO>15</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.6">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>7</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:AUTO>16</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.7">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>8</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:AUTO>17</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
<gml:featureMember>
<ogr:autoincrement_field_start fid="points.8">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:id>9</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:AUTO>18</ogr:AUTO>
</ogr:autoincrement_field_start>
</gml:featureMember>
</ogr:FeatureCollection>

View File

@ -0,0 +1,44 @@
<?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="autoincrement_field_start" type="ogr:autoincrement_field_start_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="autoincrement_field_start_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="id" 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="id2" 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="AUTO" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

View File

@ -414,7 +414,7 @@ tests:
name: expected/unique_values.gml
type: vector
- algorithm: qgis:addautoincrementalfield
- algorithm: native:addautoincrementalfield
name: Add autoincremental field
params:
INPUT:
@ -425,6 +425,33 @@ tests:
name: expected/autoincrement_field.gml
type: vector
- algorithm: native:addautoincrementalfield
name: Add autoincremental field with start value
params:
FIELD_NAME: AUTO
INPUT:
name: points.gml
type: vector
START: 10
results:
OUTPUT:
name: expected/autoincrement_field_start.gml
type: vector
- algorithm: native:addautoincrementalfield
name: Add autoincremental field with name
params:
FIELD_NAME: my_field
INPUT:
name: points.gml
type: vector
START: 0
results:
OUTPUT:
name: expected/autoincrement_field_field_name.gml
type: vector
- algorithm: native:dissolve
name: Dissolve using field
params:

View File

@ -93,6 +93,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsJoinByAttributeAlgorithm() );
addAlgorithm( new QgsJoinWithLinesAlgorithm() );
addAlgorithm( new QgsAssignProjectionAlgorithm() );
addAlgorithm( new QgsAddIncrementalFieldAlgorithm() );
}
void QgsSaveSelectedFeatures::initAlgorithm( const QVariantMap & )
@ -698,6 +699,51 @@ QgsFeature QgsAssignProjectionAlgorithm::processFeature( const QgsFeature &featu
QString QgsAddIncrementalFieldAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm adds a new integer field to a vector layer, with a sequential value for each feature.\n\n"
"This field can be used as a unique ID for features in the layer. The new attribute "
"is not added to the input layer but a new layer is generated instead.\n\n"
"The initial starting value for the incremental series can be specified." );
}
QgsAddIncrementalFieldAlgorithm *QgsAddIncrementalFieldAlgorithm::createInstance() const
{
return new QgsAddIncrementalFieldAlgorithm();
}
void QgsAddIncrementalFieldAlgorithm::initParameters( const QVariantMap & )
{
addParameter( new QgsProcessingParameterString( QStringLiteral( "FIELD_NAME" ), QObject::tr( "Field name" ), QStringLiteral( "AUTO" ) ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "START" ), QObject::tr( "Start values at" ),
QgsProcessingParameterNumber::Integer, 0, true ) );
}
QgsFields QgsAddIncrementalFieldAlgorithm::outputFields( const QgsFields &inputFields ) const
{
QgsFields outFields = inputFields;
outFields.append( QgsField( mFieldName, QVariant::LongLong ) );
return outFields;
}
bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mValue = parameterAsInt( parameters, QStringLiteral( "START" ), context );
mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
return true;
}
QgsFeature QgsAddIncrementalFieldAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback * )
{
QgsFeature f = feature;
QgsAttributes attributes = f.attributes();
attributes.append( mValue );
mValue++;
f.setAttributes( attributes );
return f;
}
void QgsSubdivideAlgorithm::initParameters( const QVariantMap & )
{
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MAX_NODES" ), QObject::tr( "Maximum nodes in parts" ), QgsProcessingParameterNumber::Integer,

View File

@ -164,6 +164,39 @@ class QgsAssignProjectionAlgorithm : public QgsProcessingFeatureBasedAlgorithm
};
/**
* Native add incremental field algorithm.
*/
class QgsAddIncrementalFieldAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{
public:
QgsAddIncrementalFieldAlgorithm() = default;
QString name() const override { return QStringLiteral( "addautoincrementalfield" ); }
QString displayName() const override { return QObject::tr( "Add autoincremental field" ); }
virtual QStringList tags() const override { return QObject::tr( "add,create,serial,primary,key,unique,field" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector table" ); }
QString shortHelpString() const override;
QgsAddIncrementalFieldAlgorithm *createInstance() const override SIP_FACTORY;
protected:
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
QString outputName() const override { return QObject::tr( "Incremented" ); }
QgsFields outputFields( const QgsFields &inputFields ) const override;
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
private:
long long mValue = 0;
QString mFieldName;
};
/**
* Native buffer algorithm.
*/