QGIS API Documentation  3.23.0-Master (eb871beae0)
qgsremappingproxyfeaturesink.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsremappingproxyfeaturesink.cpp
3  ----------------------
4  begin : April 2020
5  copyright : (C) 2020 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgslogger.h"
20 
22  : QgsFeatureSink()
23  , mDefinition( mappingDefinition )
24  , mSink( sink )
25  , mOwnsSink( ownsSink )
26 {}
27 
29 {
30  if ( mOwnsSink )
31  delete mSink;
32 }
33 
35 {
36  mContext = context;
37 }
38 
40 {
41  mTransform = QgsCoordinateTransform( mDefinition.sourceCrs(), mDefinition.destinationCrs(), context );
42 }
43 
45 {
46  QgsFeatureList res;
47 
48  mContext.setFeature( feature );
49 
50  // remap fields first
51  QgsFeature f;
52  f.setFields( mDefinition.destinationFields(), true );
53  QgsAttributes attributes;
54  const QMap< QString, QgsProperty > fieldMap = mDefinition.fieldMap();
55  for ( const QgsField &field : mDefinition.destinationFields() )
56  {
57  if ( fieldMap.contains( field.name() ) )
58  {
59  attributes.append( fieldMap.value( field.name() ).value( mContext ) );
60  }
61  else
62  {
63  attributes.append( QVariant() );
64  }
65  }
66  f.setAttributes( attributes );
67 
68  // make geometries compatible, and reproject if necessary
69  if ( feature.hasGeometry() )
70  {
71  const QVector< QgsGeometry > geometries = feature.geometry().coerceToType( mDefinition.destinationWkbType() );
72  if ( !geometries.isEmpty() )
73  {
74  res.reserve( geometries.size() );
75  for ( const QgsGeometry &geometry : geometries )
76  {
77  QgsFeature featurePart = f;
78 
79  QgsGeometry reproject = geometry;
80  try
81  {
82  reproject.transform( mTransform );
83  featurePart.setGeometry( reproject );
84  }
85  catch ( QgsCsException & )
86  {
87  QgsLogger::warning( QObject::tr( "Error reprojecting feature geometry" ) );
88  featurePart.clearGeometry();
89  }
90  res << featurePart;
91  }
92  }
93  else
94  {
95  f.clearGeometry();
96  res << f;
97  }
98  }
99  else
100  {
101  res << f;
102  }
103  return res;
104 }
105 
106 bool QgsRemappingProxyFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
107 {
108  QgsFeatureList features = remapFeature( feature );
109  return mSink->addFeatures( features, flags );
110 }
111 
112 bool QgsRemappingProxyFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
113 {
114  bool res = true;
115  for ( QgsFeature &f : features )
116  {
117  res = addFeature( f, flags ) && res;
118  }
119  return res;
120 }
121 
122 bool QgsRemappingProxyFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
123 {
124  QgsFeature f;
125  bool res = true;
126  while ( iterator.nextFeature( f ) )
127  {
128  res = addFeature( f, flags ) && res;
129  }
130  return res;
131 }
132 
134 {
135  return mSink->lastError();
136 }
137 
139 {
140  QVariantMap map;
141  map.insert( QStringLiteral( "wkb_type" ), mDestinationWkbType );
142  // we only really care about names here
143  QVariantList fieldNames;
144  for ( const QgsField &field : mDestinationFields )
145  fieldNames << field.name();
146  map.insert( QStringLiteral( "destination_field_names" ), fieldNames );
147  map.insert( QStringLiteral( "transform_source" ), mSourceCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) );
148  map.insert( QStringLiteral( "transform_dest" ), mDestinationCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) );
149 
150  QVariantMap fieldMap;
151  for ( auto it = mFieldMap.constBegin(); it != mFieldMap.constEnd(); ++it )
152  {
153  fieldMap.insert( it.key(), it.value().toVariant() );
154  }
155  map.insert( QStringLiteral( "field_map" ), fieldMap );
156 
157  return map;
158 }
159 
160 bool QgsRemappingSinkDefinition::loadVariant( const QVariantMap &map )
161 {
162  mDestinationWkbType = static_cast< QgsWkbTypes::Type >( map.value( QStringLiteral( "wkb_type" ), QgsWkbTypes::Unknown ).toInt() );
163 
164  const QVariantList fieldNames = map.value( QStringLiteral( "destination_field_names" ) ).toList();
165  QgsFields fields;
166  for ( const QVariant &field : fieldNames )
167  {
168  fields.append( QgsField( field.toString() ) );
169  }
170  mDestinationFields = fields;
171 
172  mSourceCrs = QgsCoordinateReferenceSystem::fromWkt( map.value( QStringLiteral( "transform_source" ) ).toString() );
173  mDestinationCrs = QgsCoordinateReferenceSystem::fromWkt( map.value( QStringLiteral( "transform_dest" ) ).toString() );
174 
175  const QVariantMap fieldMap = map.value( QStringLiteral( "field_map" ) ).toMap();
176  mFieldMap.clear();
177  for ( auto it = fieldMap.constBegin(); it != fieldMap.constEnd(); ++it )
178  {
179  QgsProperty p;
180  p.loadVariant( it.value() );
181  mFieldMap.insert( it.key(), p );
182  }
183 
184  return true;
185 }
186 
188 {
189  return mDestinationWkbType == other.mDestinationWkbType
190  && mDestinationFields == other.mDestinationFields
191  && mFieldMap == other.mFieldMap
192  && mSourceCrs == other.mSourceCrs
193  && mDestinationCrs == other.mDestinationCrs;
194 }
195 
197 {
198  return !( *this == other );
199 }
A vector of attributes.
Definition: qgsattributes.h:58
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
An interface for objects which accept features via addFeature(s) methods.
virtual QString lastError() const
Returns the most recent error encountered by the sink, e.g.
virtual bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())=0
Adds a list of features to the sink.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:135
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:170
QgsGeometry geometry
Definition: qgsfeature.h:67
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:159
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QVector< QgsGeometry > coerceToType(QgsWkbTypes::Type type) const
Attempts to coerce this geometry into the specified destination type.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
A store for object properties.
Definition: qgsproperty.h:231
bool loadVariant(const QVariant &property)
Loads this property from a QVariantMap, wrapped in a QVariant.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context to use when evaluating mapped field values.
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the transform context to use when reprojecting features.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
QString lastError() const override
Returns the most recent error encountered by the sink, e.g.
QgsRemappingProxyFeatureSink(const QgsRemappingSinkDefinition &mappingDefinition, QgsFeatureSink *sink, bool ownsSink=false)
Constructor for QgsRemappingProxyFeatureSink, using the specified mappingDefinition to manipulate fea...
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a single feature to the sink.
QgsFeatureList remapFeature(const QgsFeature &feature) const
Remaps a feature to a set of features compatible with the destination sink.
Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
bool operator==(const QgsRemappingSinkDefinition &other) const
QgsWkbTypes::Type destinationWkbType() const
Returns the WKB geometry type for the destination.
QMap< QString, QgsProperty > fieldMap() const
Returns the field mapping, which defines how to map the values from incoming features to destination ...
bool operator!=(const QgsRemappingSinkDefinition &other) const
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS used for reprojecting incoming features to the sink's destination CRS.
QVariant toVariant() const
Saves this remapping definition to a QVariantMap, wrapped in a QVariant.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS used for reprojecting incoming features to the sink's destination CRS.
bool loadVariant(const QVariantMap &map)
Loads this remapping definition from a QVariantMap, wrapped in a QVariant.
QgsFields destinationFields() const
Returns the fields for the destination sink.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:834
const QgsField & field
Definition: qgsfield.h:463