QGIS API Documentation 4.1.0-Master (376402f9aeb)
Loading...
Searching...
No Matches
qgsalgorithmextrude.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmextrude.cpp
3 ---------------------
4 begin : April 2026
5 copyright : (C) 2026 by Jean Felder
6 email : jean dot felder at oslandia 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
18
19#include "qgsalgorithmextrude.h"
20
21#include "qgsexception.h"
22#include "qgsgeometry.h"
23
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
28#ifdef WITH_SFCGAL
29#include "qgssfcgalgeometry.h"
30#endif
31
33
34QString QgsExtrudeAlgorithm::name() const
35{
36 return u"extrude"_s;
37}
38
39QString QgsExtrudeAlgorithm::displayName() const
40{
41 return QObject::tr( "Extrude" );
42}
43
44QStringList QgsExtrudeAlgorithm::tags() const
45{
46 return QObject::tr( "extrude,extrusion,3d,volume" ).split( ',' );
47}
48
49QString QgsExtrudeAlgorithm::group() const
50{
51 return QObject::tr( "Vector geometry" );
52}
53
54QString QgsExtrudeAlgorithm::groupId() const
55{
56 return u"vectorgeometry"_s;
57}
58
59QString QgsExtrudeAlgorithm::shortHelpString() const
60{
61 return QObject::tr(
62 "This algorithm generates 3D geometries by extruding 2D polygon features along a specified direction.\n\n"
63 "Each feature is displaced according to the X, Y, and Z extrusion parameters: "
64 "X and Y control the horizontal displacement, while Z controls the vertical elevation. "
65 "Setting only the Z parameter produces vertical extrusions, whereas combining X, Y, and Z "
66 "allows the creation of non-vertical extrusions. Negative values are supported, enabling extrusions "
67 "in the opposite direction.\n\n"
68 "If the input features already carry Z values, those values are preserved and used as the base "
69 "elevation of the extruded geometry.\n\n"
70 "For MultiPolygon geometries, each part is extruded separately, producing one output feature per part.\n\n"
71 "Output geometries are of type PolyhedralSurfaceZ, representing the extruded surface of each input feature."
72 );
73}
74
75QString QgsExtrudeAlgorithm::shortDescription() const
76{
77 return QObject::tr( "Generates a 3D extrusion from 2D polygon features." );
78}
79
80QgsExtrudeAlgorithm *QgsExtrudeAlgorithm::createInstance() const
81{
82 return new QgsExtrudeAlgorithm();
83}
84
85QList<int> QgsExtrudeAlgorithm::inputLayerTypes() const
86{
87 return QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon );
88}
89
90QString QgsExtrudeAlgorithm::outputName() const
91{
92 return QObject::tr( "Extrusion" );
93}
94
95Qgis::ProcessingSourceType QgsExtrudeAlgorithm::outputLayerType() const
96{
98}
99
100Qgis::WkbType QgsExtrudeAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
101{
102 Q_UNUSED( inputWkbType )
104}
105
106void QgsExtrudeAlgorithm::initParameters( const QVariantMap & )
107{
108 auto xExtrude = std::make_unique<QgsProcessingParameterNumber>( u"EXTRUDE_X"_s, QObject::tr( "Extrusion (x-axis)" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
109 xExtrude->setIsDynamic( true );
110 xExtrude->setDynamicPropertyDefinition( QgsPropertyDefinition( u"EXTRUDE_X"_s, QObject::tr( "Extrusion (x-axis)" ), QgsPropertyDefinition::Double ) );
111 xExtrude->setDynamicLayerParameterName( u"INPUT"_s );
112 addParameter( xExtrude.release() );
113
114 auto yExtrude = std::make_unique<QgsProcessingParameterNumber>( u"EXTRUDE_Y"_s, QObject::tr( "Extrusion (y-axis)" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
115 yExtrude->setIsDynamic( true );
116 yExtrude->setDynamicPropertyDefinition( QgsPropertyDefinition( u"EXTRUDE_Y"_s, QObject::tr( "Extrusion (y-axis)" ), QgsPropertyDefinition::Double ) );
117 yExtrude->setDynamicLayerParameterName( u"INPUT"_s );
118 addParameter( yExtrude.release() );
119
120 auto zExtrude = std::make_unique<QgsProcessingParameterNumber>( u"EXTRUDE_Z"_s, QObject::tr( "Extrusion (z-axis)" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
121 zExtrude->setIsDynamic( true );
122 zExtrude->setDynamicPropertyDefinition( QgsPropertyDefinition( u"EXTRUDE_Z"_s, QObject::tr( "Extrusion (z-axis)" ), QgsPropertyDefinition::Double ) );
123 zExtrude->setDynamicLayerParameterName( u"INPUT"_s );
124 addParameter( zExtrude.release() );
125}
126
127bool QgsExtrudeAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
128{
129 Q_UNUSED( feedback )
130
131#ifdef WITH_SFCGAL
132 mExtrudeX = parameterAsDouble( parameters, u"EXTRUDE_X"_s, context );
133 mDynamicExtrudeX = QgsProcessingParameters::isDynamic( parameters, u"EXTRUDE_X"_s );
134 if ( mDynamicExtrudeX )
135 mExtrudeXProperty = parameters.value( u"EXTRUDE_X"_s ).value<QgsProperty>();
136
137 mExtrudeY = parameterAsDouble( parameters, u"EXTRUDE_Y"_s, context );
138 mDynamicExtrudeY = QgsProcessingParameters::isDynamic( parameters, u"EXTRUDE_Y"_s );
139 if ( mDynamicExtrudeY )
140 mExtrudeYProperty = parameters.value( u"EXTRUDE_Y"_s ).value<QgsProperty>();
141
142 mExtrudeZ = parameterAsDouble( parameters, u"EXTRUDE_Z"_s, context );
143 mDynamicExtrudeZ = QgsProcessingParameters::isDynamic( parameters, u"EXTRUDE_Z"_s );
144 if ( mDynamicExtrudeZ )
145 mExtrudeZProperty = parameters.value( u"EXTRUDE_Z"_s ).value<QgsProperty>();
146
147 return true;
148#else
149 Q_UNUSED( parameters )
150 Q_UNUSED( context )
151 throw QgsProcessingException( QObject::tr( "This processing algorithm requires a QGIS installation with SFCGAL support enabled. Please use a version of QGIS that includes SFCGAL." ) );
152#endif
153}
154
155#ifdef WITH_SFCGAL
156std::optional<QgsGeometry> QgsExtrudeAlgorithm::extrudePolygon( const QgsAbstractGeometry *polygon, const QgsVector3D &extrusion, const QgsFeatureId &featureId, QgsProcessingFeedback *feedback )
157{
158 try
159 {
160 QgsSfcgalGeometry inputSfcgalGeometry( polygon );
161 if ( inputSfcgalGeometry.isEmpty() )
162 {
163 return std::nullopt;
164 }
165
166 std::unique_ptr<QgsSfcgalGeometry> outputSfcgalGeometry = inputSfcgalGeometry.extrude( extrusion );
167 return QgsGeometry( outputSfcgalGeometry->asQgisGeometry() );
168 }
169 catch ( const QgsSfcgalException &exception )
170 {
171 feedback->reportError( QObject::tr( "Cannot calculate extrusion for feature %1: %2" ).arg( featureId ).arg( exception.what() ) );
172 return std::nullopt;
173 }
174}
175#endif
176
177QgsFeatureList QgsExtrudeAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
178{
179#ifdef WITH_SFCGAL
180 if ( !feature.hasGeometry() )
181 {
182 return QgsFeatureList() << feature;
183 }
184
185 double extrudeX = mExtrudeX;
186 if ( mDynamicExtrudeX )
187 {
188 extrudeX = mExtrudeXProperty.valueAsDouble( context.expressionContext(), extrudeX );
189 }
190
191 double extrudeY = mExtrudeY;
192 if ( mDynamicExtrudeY )
193 {
194 extrudeY = mExtrudeYProperty.valueAsDouble( context.expressionContext(), extrudeY );
195 }
196
197 double extrudeZ = mExtrudeZ;
198 if ( mDynamicExtrudeZ )
199 {
200 extrudeZ = mExtrudeZProperty.valueAsDouble( context.expressionContext(), extrudeZ );
201 }
202
203 const QgsVector3D extrusion( extrudeX, extrudeY, extrudeZ );
204
205 QgsFeatureList outputFeatures;
206 const QgsGeometry inputGeometry = feature.geometry();
207
208 // For MultiPolygons, each part is extruded separately
209 if ( inputGeometry.isMultipart() )
210 {
211 for ( auto partIt = inputGeometry.const_parts_begin(); partIt != inputGeometry.const_parts_end(); ++partIt )
212 {
213 std::optional<QgsGeometry> extruded = extrudePolygon( *partIt, extrusion, feature.id(), feedback );
214 if ( extruded.has_value() )
215 {
216 QgsFeature modifiedFeature;
217 modifiedFeature.setGeometry( extruded.value() );
218 modifiedFeature.setAttributes( feature.attributes() );
219 outputFeatures << modifiedFeature;
220 }
221 }
222 }
223 else
224 {
225 std::optional<QgsGeometry> extruded = extrudePolygon( inputGeometry.constGet(), extrusion, feature.id(), feedback );
226 if ( extruded.has_value() )
227 {
228 QgsFeature modifiedFeature = feature;
229 modifiedFeature.setGeometry( extruded.value() );
230 outputFeatures << modifiedFeature;
231 }
232 }
233
234 return outputFeatures;
235#else
236 Q_UNUSED( feature )
237 Q_UNUSED( context )
238 Q_UNUSED( feedback )
239 throw QgsProcessingException( QObject::tr( "This processing algorithm requires a QGIS installation with SFCGAL support enabled. Please use a version of QGIS that includes SFCGAL." ) );
240#endif
241}
242
ProcessingSourceType
Processing data source types.
Definition qgis.h:3712
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3717
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ PolyhedralSurfaceZ
PolyhedralSurfaceZ.
Definition qgis.h:326
@ Double
Double/float values.
Definition qgis.h:3988
Abstract base class for all geometries.
QString what() const
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
QgsAttributes attributes
Definition qgsfeature.h:69
QgsFeatureId id
Definition qgsfeature.h:68
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:71
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
static bool isDynamic(const QVariantMap &parameters, const QString &name)
Returns true if the parameter with matching name is a dynamic parameter, and must be evaluated once f...
Definition for a property.
Definition qgsproperty.h:47
@ Double
Double value (including negative values).
Definition qgsproperty.h:56
A store for object properties.
Custom exception class for SfCGAL related operations.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
QList< QgsFeature > QgsFeatureList
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features