32 SetMarkerRotationVisitor(
const QString &rotationField )
33 : mRotationField( rotationField )
49 QString mRotationField;
57 SetMarkerRotationPostProcessor( std::unique_ptr< QgsFeatureRenderer > renderer,
const QString &rotationField )
58 : mRenderer( std::move( renderer ) )
59 , mRotationField( rotationField )
64 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
66 SetMarkerRotationVisitor visitor( mRotationField );
67 mRenderer->accept( &visitor );
68 vl->setRenderer( mRenderer.release() );
75 std::unique_ptr<QgsFeatureRenderer> mRenderer;
76 QString mRotationField;
79 QString QgsAngleToNearestAlgorithm::name()
const
81 return QStringLiteral(
"angletonearest" );
84 QString QgsAngleToNearestAlgorithm::displayName()
const
86 return QObject::tr(
"Align points to features" );
89 QStringList QgsAngleToNearestAlgorithm::tags()
const
91 return QObject::tr(
"align,marker,stroke,fill,orient,points,lines,angles,rotation,rotate" ).split(
',' );
94 QString QgsAngleToNearestAlgorithm::group()
const
96 return QObject::tr(
"Cartography" );
99 QString QgsAngleToNearestAlgorithm::groupId()
const
101 return QStringLiteral(
"cartography" );
104 QgsAngleToNearestAlgorithm::~QgsAngleToNearestAlgorithm() =
default;
106 void QgsAngleToNearestAlgorithm::initAlgorithm(
const QVariantMap &configuration )
108 mIsInPlace = configuration.value( QStringLiteral(
"IN_PLACE" ) ).toBool();
113 QObject::tr(
"Reference layer" ) ) );
116 QObject::tr(
"Maximum distance to consider" ), QVariant(), QStringLiteral(
"INPUT" ),
true, 0 ) );
119 addParameter(
new QgsProcessingParameterString( QStringLiteral(
"FIELD_NAME" ), QObject::tr(
"Angle field name" ), QStringLiteral(
"rotation" ) ) );
121 addParameter(
new QgsProcessingParameterField( QStringLiteral(
"FIELD_NAME" ), QObject::tr(
"Angle field name" ), QStringLiteral(
"rotation" ), QStringLiteral(
"INPUT" ) ) );
123 addParameter(
new QgsProcessingParameterBoolean( QStringLiteral(
"APPLY_SYMBOLOGY" ), QObject::tr(
"Automatically apply symbology" ),
true ) );
128 QgsProcessingAlgorithm::Flags QgsAngleToNearestAlgorithm::flags()
const
135 QString QgsAngleToNearestAlgorithm::shortHelpString()
const
137 return QObject::tr(
"This algorithm calculates the rotation required to align point features with their nearest "
138 "feature from another reference layer. A new field is added to the output layer which is filled with the angle "
139 "(in degrees, clockwise) to the nearest reference feature.\n\n"
140 "Optionally, the output layer's symbology can be set to automatically use the calculated rotation "
141 "field to rotate marker symbols.\n\n"
142 "If desired, a maximum distance to use when aligning points can be set, to avoid aligning isolated points "
143 "to distant features." );
146 QString QgsAngleToNearestAlgorithm::shortDescription()
const
148 return QObject::tr(
"Rotates point features to align them to nearby features." );
151 QgsAngleToNearestAlgorithm *QgsAngleToNearestAlgorithm::createInstance()
const
153 return new QgsAngleToNearestAlgorithm();
156 bool QgsAngleToNearestAlgorithm::supportInPlaceEdit(
const QgsMapLayer *layer )
const
158 if (
const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
169 if (
QgsVectorLayer *sourceLayer = parameterAsVectorLayer( parameters, QStringLiteral(
"INPUT" ), context ) )
171 mSourceRenderer.reset( sourceLayer->renderer()->clone() );
180 const double maxDistance = parameters.value( QStringLiteral(
"MAX_DISTANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral(
"MAX_DISTANCE" ), context ) : std::numeric_limits< double >::quiet_NaN();
181 std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
185 std::unique_ptr< QgsProcessingFeatureSource > referenceSource( parameterAsSource( parameters, QStringLiteral(
"REFERENCE_LAYER" ), context ) );
186 if ( !referenceSource )
189 const QString fieldName = parameterAsString( parameters, QStringLiteral(
"FIELD_NAME" ), context );
203 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, dest, outFields,
204 input->wkbType(), input->sourceCrs() ) );
205 if ( parameters.value( QStringLiteral(
"OUTPUT" ) ).isValid() && !sink )
210 double step = referenceSource->featureCount() > 0 ? 50.0 / referenceSource->featureCount() : 1;
226 step = input->featureCount() > 0 ? 50.0 / input->featureCount() : 1;
241 if ( !f.hasGeometry() )
244 attributes.append( QVariant() );
246 attributes[ fieldIndex ] = QVariant();
247 f.setAttributes( attributes );
253 const QList< QgsFeatureId > nearest = index.nearestNeighbor( f.geometry(), 1, std::isnan( maxDistance ) ? 0 : maxDistance );
254 if ( nearest.empty() )
256 feedback->
pushInfo( QObject::tr(
"No matching features found within search distance" ) );
258 attributes.append( QVariant() );
260 attributes[ fieldIndex ] = QVariant();
261 f.setAttributes( attributes );
267 if ( nearest.count() > 1 )
269 feedback->
pushInfo( QObject::tr(
"Multiple matching features found at same distance from search feature, found %n feature(s)",
nullptr, nearest.count() ) );
276 attributes.append( line->startPoint().azimuth( line->endPoint() ) );
278 attributes[ fieldIndex ] = line->startPoint().azimuth( line->endPoint() );
283 attributes.append( QVariant() );
285 attributes[ fieldIndex ] = QVariant();
287 f.setAttributes( attributes );
294 const bool applySymbology = parameterAsBool( parameters, QStringLiteral(
"APPLY_SYMBOLOGY" ), context );
295 if ( applySymbology )
301 QVariantMap inPlaceParams = parameters;
302 inPlaceParams.insert( QStringLiteral(
"INPUT" ), parameters.value( QStringLiteral(
"INPUT" ) ).value< QgsProcessingFeatureSourceDefinition >().source );
303 if (
QgsVectorLayer *sourceLayer = parameterAsVectorLayer( inPlaceParams, QStringLiteral(
"INPUT" ), context ) )
305 std::unique_ptr< QgsFeatureRenderer > sourceRenderer( sourceLayer->renderer()->clone() );
306 SetMarkerRotationPostProcessor processor( std::move( sourceRenderer ), fieldName );
307 processor.postProcessLayer( sourceLayer, context, feedback );
317 outputs.insert( QStringLiteral(
"OUTPUT" ), dest );