QGIS API Documentation 4.3.0-Master (ffcfc20b9b4)
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 QGS_MARK_ALGORITHM_SOURCE
180
181#ifdef WITH_SFCGAL
182 if ( !feature.hasGeometry() )
183 {
184 return QgsFeatureList() << feature;
185 }
186
187 double extrudeX = mExtrudeX;
188 if ( mDynamicExtrudeX )
189 {
190 extrudeX = mExtrudeXProperty.valueAsDouble( context.expressionContext(), extrudeX );
191 }
192
193 double extrudeY = mExtrudeY;
194 if ( mDynamicExtrudeY )
195 {
196 extrudeY = mExtrudeYProperty.valueAsDouble( context.expressionContext(), extrudeY );
197 }
198
199 double extrudeZ = mExtrudeZ;
200 if ( mDynamicExtrudeZ )
201 {
202 extrudeZ = mExtrudeZProperty.valueAsDouble( context.expressionContext(), extrudeZ );
203 }
204
205 const QgsVector3D extrusion( extrudeX, extrudeY, extrudeZ );
206
207 QgsFeatureList outputFeatures;
208 const QgsGeometry inputGeometry = feature.geometry();
209
210 // For MultiPolygons, each part is extruded separately
211 if ( inputGeometry.isMultipart() )
212 {
213 for ( auto partIt = inputGeometry.const_parts_begin(); partIt != inputGeometry.const_parts_end(); ++partIt )
214 {
215 std::optional<QgsGeometry> extruded = extrudePolygon( *partIt, extrusion, feature.id(), feedback );
216 if ( extruded.has_value() )
217 {
218 QgsFeature modifiedFeature;
219 modifiedFeature.setGeometry( extruded.value() );
220 modifiedFeature.setAttributes( feature.attributes() );
221 outputFeatures << modifiedFeature;
222 }
223 }
224 }
225 else
226 {
227 std::optional<QgsGeometry> extruded = extrudePolygon( inputGeometry.constGet(), extrusion, feature.id(), feedback );
228 if ( extruded.has_value() )
229 {
230 QgsFeature modifiedFeature = feature;
231 modifiedFeature.setGeometry( extruded.value() );
232 outputFeatures << modifiedFeature;
233 }
234 }
235
236 return outputFeatures;
237#else
238 Q_UNUSED( feature )
239 Q_UNUSED( context )
240 Q_UNUSED( feedback )
241 throw QgsProcessingException( QObject::tr( "This processing algorithm requires a QGIS installation with SFCGAL support enabled. Please use a version of QGIS that includes SFCGAL." ) );
242#endif
243}
244
ProcessingSourceType
Processing data source types.
Definition qgis.h:3747
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3752
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:4023
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:64
QgsFeatureId id
Definition qgsfeature.h:63
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:66
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