Skip to content

Commit

Permalink
Allow selection of a subset of fields to keep for hub lines algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Oct 12, 2017
1 parent cc19d0a commit bd24c8b
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 4 deletions.
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ hub_lines_field_subset.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>-4.1675</gml:Y></gml:coord>
<gml:coord><gml:X>7</gml:X><gml:Y>3.8825</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,1 5.07625,-2.1725</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>1</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:name>point 1</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,3 5.82,3.8825</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>2</ogr:id>
<ogr:id2>1</ogr:id2>
<ogr:name>point 2</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,2 1.62,1.4675</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>3</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:name>point 3</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,2 6.68625,1.23125</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>4</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:name>point 4</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,2 1.27875,-3.66875</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>4</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:name>point 4a</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,2 3.81625,-4.1675</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>4</ogr:id>
<ogr:id2>2</ogr:id2>
<ogr:name>point 4b</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
<gml:featureMember>
<ogr:hub_lines_field_subset fid="hub_lines_field_subset.6">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-1 6.82625,-2.79375</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:id>8</ogr:id>
<ogr:id2>0</ogr:id2>
<ogr:name>point 8</ogr:name>
</ogr:hub_lines_field_subset>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -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="hub_lines_field_subset" type="ogr:hub_lines_field_subset_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="hub_lines_field_subset_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" 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="name" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
21 changes: 21 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -2500,6 +2500,27 @@ tests:
fid: skip
fid_2: skip

- algorithm: native:hublines
name: Hub lines subset of fields
params:
HUBS:
name: points.gml
type: vector
HUB_FIELD: id
HUB_FIELDS:
- id
- id2
SPOKES:
name: custom/spoke_points.gml
type: vector
SPOKE_FIELD: id
SPOKE_FIELDS:
- name
results:
OUTPUT:
name: expected/hub_lines_field_subset.gml
type: vector

- algorithm: qgis:pointstopath
name: Points to path (non grouped)
params:
Expand Down
96 changes: 92 additions & 4 deletions src/core/processing/qgsnativealgorithms.cpp
Expand Up @@ -2885,11 +2885,22 @@ void QgsJoinWithLinesAlgorithm::initAlgorithm( const QVariantMap & )
QObject::tr( "Hub layer" ) ) );
addParameter( new QgsProcessingParameterField( QStringLiteral( "HUB_FIELD" ),
QObject::tr( "Hub ID field" ), QVariant(), QStringLiteral( "HUBS" ) ) );

addParameter( new QgsProcessingParameterField( QStringLiteral( "HUB_FIELDS" ),
QObject::tr( "Hub layer fields to copy (leave empty to copy all fields)" ),
QVariant(), QStringLiteral( "HUBS" ), QgsProcessingParameterField::Any,
true, true ) );

addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "SPOKES" ),
QObject::tr( "Spoke layer" ) ) );
addParameter( new QgsProcessingParameterField( QStringLiteral( "SPOKE_FIELD" ),
QObject::tr( "Spoke ID field" ), QVariant(), QStringLiteral( "SPOKES" ) ) );

addParameter( new QgsProcessingParameterField( QStringLiteral( "SPOKE_FIELDS" ),
QObject::tr( "Spoke layer fields to copy (leave empty to copy all fields)" ),
QVariant(), QStringLiteral( "SPOKES" ), QgsProcessingParameterField::Any,
true, true ) );

addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Hub lines" ), QgsProcessing::TypeVectorLine ) );
}

Expand Down Expand Up @@ -2917,13 +2928,69 @@ QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap &para

QString fieldHubName = parameterAsString( parameters, QStringLiteral( "HUB_FIELD" ), context );
int fieldHubIndex = hubSource->fields().lookupField( fieldHubName );
const QStringList hubFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "HUB_FIELDS" ), context );

QString fieldSpokeName = parameterAsString( parameters, QStringLiteral( "SPOKE_FIELD" ), context );
int fieldSpokeIndex = spokeSource->fields().lookupField( fieldSpokeName );
const QStringList spokeFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "SPOKE_FIELDS" ), context );

if ( fieldHubIndex < 0 || fieldSpokeIndex < 0 )
throw QgsProcessingException( QObject::tr( "Invalid ID field" ) );

QgsFields fields = QgsProcessingUtils::combineFields( hubSource->fields(), spokeSource->fields() );
QgsFields hubOutFields;
QgsAttributeList hubFieldIndices;
if ( hubFieldsToCopy.empty() )
{
hubOutFields = hubSource->fields();
for ( int i = 0; i < hubOutFields.count(); ++i )
{
hubFieldIndices << i;
}
}
else
{
for ( const QString &field : hubFieldsToCopy )
{
int index = hubSource->fields().lookupField( field );
if ( index >= 0 )
{
hubFieldIndices << index;
hubOutFields.append( hubSource->fields().at( index ) );
}
}
}

QgsAttributeList hubFields2Fetch = hubFieldIndices;
hubFields2Fetch << fieldHubIndex;

QgsFields spokeOutFields;
QgsAttributeList spokeFieldIndices;
if ( spokeFieldsToCopy.empty() )
{
spokeOutFields = spokeSource->fields();
for ( int i = 0; i < spokeOutFields.count(); ++i )
{
spokeFieldIndices << i;
}
}
else
{
for ( const QString &field : spokeFieldsToCopy )
{
int index = spokeSource->fields().lookupField( field );
if ( index >= 0 )
{
spokeFieldIndices << index;
spokeOutFields.append( spokeSource->fields().at( index ) );
}
}
}

QgsAttributeList spokeFields2Fetch = spokeFieldIndices;
spokeFields2Fetch << fieldSpokeIndex;


QgsFields fields = QgsProcessingUtils::combineFields( hubOutFields, spokeOutFields );

QgsWkbTypes::Type outType = QgsWkbTypes::LineString;
bool hasZ = false;
Expand Down Expand Up @@ -2959,7 +3026,7 @@ QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap &para
return p;
};

QgsFeatureIterator hubFeatures = hubSource->getFeatures();
QgsFeatureIterator hubFeatures = hubSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( hubFields2Fetch ) );
double step = hubSource->featureCount() > 0 ? 100.0 / hubSource->featureCount() : 1;
int i = 0;
QgsFeature hubFeature;
Expand All @@ -2977,9 +3044,18 @@ QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap &para
continue;

QgsPoint hubPoint = getPointFromFeature( hubFeature );
QgsAttributes hubAttributes = hubFeature.attributes();

// only keep selected attributes
QgsAttributes hubAttributes;
for ( int j = 0; j < hubFeature.attributes().count(); ++j )
{
if ( !hubFieldIndices.contains( j ) )
continue;
hubAttributes << hubFeature.attribute( j );
}

QgsFeatureRequest spokeRequest = QgsFeatureRequest().setDestinationCrs( hubSource->sourceCrs() );
spokeRequest.setSubsetOfAttributes( spokeFields2Fetch );
spokeRequest.setFilterExpression( QgsExpression::createFieldEqualityExpression( fieldSpokeName, hubFeature.attribute( fieldHubIndex ) ) );

QgsFeatureIterator spokeFeatures = spokeSource->getFeatures( spokeRequest );
Expand All @@ -2990,13 +3066,25 @@ QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap &para
{
break;
}
if ( !spokeFeature.hasGeometry() )
continue;

QgsPoint spokePoint = getPointFromFeature( spokeFeature );
QgsGeometry line( new QgsLineString( QVector< QgsPoint >() << hubPoint << spokePoint ) );

QgsFeature outFeature;
QgsAttributes outAttributes = hubAttributes;
outAttributes.append( spokeFeature.attributes() );

// only keep selected attributes
QgsAttributes spokeAttributes;
for ( int j = 0; j < spokeFeature.attributes().count(); ++j )
{
if ( !spokeFieldIndices.contains( j ) )
continue;
spokeAttributes << spokeFeature.attribute( j );
}

outAttributes.append( spokeAttributes );
outFeature.setAttributes( outAttributes );
outFeature.setGeometry( line );
sink->addFeature( outFeature, QgsFeatureSink::FastInsert );
Expand Down

0 comments on commit bd24c8b

Please sign in to comment.