31 SetMarkerRotationVisitor(
const QString &rotationField )
32 : mRotationField( rotationField )
48 QString mRotationField;
56 SetMarkerRotationPostProcessor( std::unique_ptr< QgsFeatureRenderer > renderer,
const QString &rotationField )
57 : mRenderer( std::move( renderer ) )
58 , mRotationField( rotationField )
63 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
65 SetMarkerRotationVisitor visitor( mRotationField );
66 mRenderer->accept( &visitor );
67 vl->setRenderer( mRenderer.release() );
74 std::unique_ptr<QgsFeatureRenderer> mRenderer;
75 QString mRotationField;
78 QString QgsAngleToNearestAlgorithm::name()
const
80 return QStringLiteral(
"angletonearest" );
83 QString QgsAngleToNearestAlgorithm::displayName()
const
85 return QObject::tr(
"Align points to features" );
88 QStringList QgsAngleToNearestAlgorithm::tags()
const
90 return QObject::tr(
"align,marker,stroke,fill,orient,points,lines,angles,rotation,rotate" ).split(
',' );
93 QString QgsAngleToNearestAlgorithm::group()
const
95 return QObject::tr(
"Cartography" );
98 QString QgsAngleToNearestAlgorithm::groupId()
const
100 return QStringLiteral(
"cartography" );
103 QgsAngleToNearestAlgorithm::~QgsAngleToNearestAlgorithm() =
default;
105 void QgsAngleToNearestAlgorithm::initAlgorithm(
const QVariantMap &configuration )
107 mIsInPlace = configuration.value( QStringLiteral(
"IN_PLACE" ) ).toBool();
112 QObject::tr(
"Reference layer" ) ) );
115 QObject::tr(
"Maximum distance to consider" ), QVariant(), QStringLiteral(
"INPUT" ),
true, 0 ) );
118 addParameter(
new QgsProcessingParameterString( QStringLiteral(
"FIELD_NAME" ), QObject::tr(
"Angle field name" ), QStringLiteral(
"rotation" ) ) );
120 addParameter(
new QgsProcessingParameterField( QStringLiteral(
"FIELD_NAME" ), QObject::tr(
"Angle field name" ), QStringLiteral(
"rotation" ), QStringLiteral(
"INPUT" ) ) );
122 addParameter(
new QgsProcessingParameterBoolean( QStringLiteral(
"APPLY_SYMBOLOGY" ), QObject::tr(
"Automatically apply symbology" ),
true ) );
127 QgsProcessingAlgorithm::Flags QgsAngleToNearestAlgorithm::flags()
const
134 QString QgsAngleToNearestAlgorithm::shortHelpString()
const
136 return QObject::tr(
"This algorithm calculates the rotation required to align point features with their nearest "
137 "feature from another reference layer. A new field is added to the output layer which is filled with the angle "
138 "(in degrees, clockwise) to the nearest reference feature.\n\n"
139 "Optionally, the output layer's symbology can be set to automatically use the calculated rotation "
140 "field to rotate marker symbols.\n\n"
141 "If desired, a maximum distance to use when aligning points can be set, to avoid aligning isolated points "
142 "to distant features." );
145 QString QgsAngleToNearestAlgorithm::shortDescription()
const
147 return QObject::tr(
"Rotates point features to align them to nearby features." );
150 QgsAngleToNearestAlgorithm *QgsAngleToNearestAlgorithm::createInstance()
const
152 return new QgsAngleToNearestAlgorithm();
155 bool QgsAngleToNearestAlgorithm::supportInPlaceEdit(
const QgsMapLayer *layer )
const
157 if (
const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
168 if (
QgsVectorLayer *sourceLayer = parameterAsVectorLayer( parameters, QStringLiteral(
"INPUT" ), context ) )
170 mSourceRenderer.reset( sourceLayer->renderer()->clone() );
179 const double maxDistance = parameters.value( QStringLiteral(
"MAX_DISTANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral(
"MAX_DISTANCE" ), context ) : std::numeric_limits< double >::quiet_NaN();
180 std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
184 std::unique_ptr< QgsProcessingFeatureSource > referenceSource( parameterAsSource( parameters, QStringLiteral(
"REFERENCE_LAYER" ), context ) );
185 if ( !referenceSource )
188 const QString fieldName = parameterAsString( parameters, QStringLiteral(
"FIELD_NAME" ), context );
202 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, dest, outFields,
203 input->wkbType(), input->sourceCrs() ) );
204 if ( parameters.value( QStringLiteral(
"OUTPUT" ) ).isValid() && !sink )
209 double step = referenceSource->featureCount() > 0 ? 50.0 / referenceSource->featureCount() : 1;
225 step = input->featureCount() > 0 ? 50.0 / input->featureCount() : 1;
240 if ( !f.hasGeometry() )
243 attributes.append( QVariant() );
245 attributes[ fieldIndex ] = QVariant();
246 f.setAttributes( attributes );
251 const QList< QgsFeatureId > nearest = index.nearestNeighbor( f.geometry(), 1, std::isnan( maxDistance ) ? 0 : maxDistance );
252 if ( nearest.empty() )
254 feedback->
pushInfo( QObject::tr(
"No matching features found within search distance" ) );
256 attributes.append( QVariant() );
258 attributes[ fieldIndex ] = QVariant();
259 f.setAttributes( attributes );
264 if ( nearest.count() > 1 )
266 feedback->
pushInfo( QObject::tr(
"Multiple matching features found at same distance from search feature, found %1 features" ).arg( nearest.count() ) );
273 attributes.append( line->startPoint().azimuth( line->endPoint() ) );
275 attributes[ fieldIndex ] = line->startPoint().azimuth( line->endPoint() );
280 attributes.append( QVariant() );
282 attributes[ fieldIndex ] = QVariant();
284 f.setAttributes( attributes );
290 const bool applySymbology = parameterAsBool( parameters, QStringLiteral(
"APPLY_SYMBOLOGY" ), context );
291 if ( applySymbology )
297 QVariantMap inPlaceParams = parameters;
298 inPlaceParams.insert( QStringLiteral(
"INPUT" ), parameters.value( QStringLiteral(
"INPUT" ) ).value< QgsProcessingFeatureSourceDefinition >().source );
299 if (
QgsVectorLayer *sourceLayer = parameterAsVectorLayer( inPlaceParams, QStringLiteral(
"INPUT" ), context ) )
301 std::unique_ptr< QgsFeatureRenderer > sourceRenderer( sourceLayer->renderer()->clone() );
302 SetMarkerRotationPostProcessor processor( std::move( sourceRenderer ), fieldName );
303 processor.postProcessLayer( sourceLayer, context, feedback );
313 outputs.insert( QStringLiteral(
"OUTPUT" ), dest );