QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgspolygon3dsymbol_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspolygon3dsymbol_p.cpp
3  --------------------------------------
4  Date : July 2017
5  Copyright : (C) 2017 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgspolygon3dsymbol_p.h"
17 
18 #include "qgspolygon3dsymbol.h"
20 #include "qgs3dmapsettings.h"
21 #include "qgs3dutils.h"
22 
23 #include <Qt3DCore/QTransform>
24 #include <Qt3DRender/QEffect>
25 #include <Qt3DRender/QTechnique>
26 #include <Qt3DRender/QCullFace>
27 
28 #include "qgsvectorlayer.h"
29 #include "qgsmultipolygon.h"
30 
31 
32 static QgsExpressionContext _expressionContext3D()
33 {
37  return ctx;
38 }
39 
40 static QSet<QString> _requiredAttributes( const QgsPolygon3DSymbol &symbol, QgsVectorLayer *layer )
41 {
42  QgsExpressionContext ctx( _expressionContext3D() );
43  ctx.setFields( layer->fields() );
44  //symbol.dataDefinedProperties().prepare( ctx );
45  return symbol.dataDefinedProperties().referencedFields( ctx );
46 }
47 
48 
50 
51 QgsPolygon3DSymbolEntity::QgsPolygon3DSymbolEntity( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol, Qt3DCore::QNode *parent )
52  : Qt3DCore::QEntity( parent )
53 {
54  addEntityForSelectedPolygons( map, layer, symbol );
55  addEntityForNotSelectedPolygons( map, layer, symbol );
56 }
57 
58 void QgsPolygon3DSymbolEntity::addEntityForSelectedPolygons( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol )
59 {
60  // build the default material
61  Qt3DExtras::QPhongMaterial *mat = material( symbol );
62 
63  // update the material with selection colors
64  mat->setDiffuse( map.selectionColor() );
65  mat->setAmbient( map.selectionColor().darker() );
66 
67  // build a transform function
68  Qt3DCore::QTransform *tform = new Qt3DCore::QTransform;
69  tform->setTranslation( QVector3D( 0, 0, 0 ) );
70 
71  // build the feature request to select features
73  req.setDestinationCrs( map.crs(), map.transformContext() );
74  req.setSubsetOfAttributes( _requiredAttributes( symbol, layer ), layer->fields() );
75  req.setFilterFids( layer->selectedFeatureIds() );
76 
77  // build the entity
78  QgsPolygon3DSymbolEntityNode *entity = new QgsPolygon3DSymbolEntityNode( map, layer, symbol, req );
79  entity->addComponent( mat );
80  entity->addComponent( tform );
81  entity->setParent( this );
82 }
83 
84 void QgsPolygon3DSymbolEntity::addEntityForNotSelectedPolygons( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol )
85 {
86  // build the default material
87  Qt3DExtras::QPhongMaterial *mat = material( symbol );
88 
89  // build a transform function
90  Qt3DCore::QTransform *tform = new Qt3DCore::QTransform;
91  tform->setTranslation( QVector3D( 0, 0, 0 ) );
92 
93  // build the feature request to select features
95  req.setSubsetOfAttributes( _requiredAttributes( symbol, layer ), layer->fields() );
96  req.setDestinationCrs( map.crs(), map.transformContext() );
97 
98  QgsFeatureIds notSelected = layer->allFeatureIds();
99  notSelected.subtract( layer->selectedFeatureIds() );
100  req.setFilterFids( notSelected );
101 
102  // build the entity
103  QgsPolygon3DSymbolEntityNode *entity = new QgsPolygon3DSymbolEntityNode( map, layer, symbol, req );
104  entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral( "main" ) ); // temporary measure to distinguish between "selected" and "main"
105  entity->addComponent( mat );
106  entity->addComponent( tform );
107  entity->setParent( this );
108 }
109 
110 static Qt3DRender::QCullFace::CullingMode _qt3DcullingMode( Qgs3DTypes::CullingMode mode )
111 {
112  switch ( mode )
113  {
114  case Qgs3DTypes::NoCulling: return Qt3DRender::QCullFace::NoCulling;
115  case Qgs3DTypes::Front: return Qt3DRender::QCullFace::Front;
116  case Qgs3DTypes::Back: return Qt3DRender::QCullFace::Back;
117  case Qgs3DTypes::FrontAndBack: return Qt3DRender::QCullFace::FrontAndBack;
118  }
119  return Qt3DRender::QCullFace::NoCulling;
120 }
121 
122 Qt3DExtras::QPhongMaterial *QgsPolygon3DSymbolEntity::material( const QgsPolygon3DSymbol &symbol ) const
123 {
124  Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial;
125 
126  // front/back side culling
127  auto techniques = material->effect()->techniques();
128  for ( auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
129  {
130  auto renderPasses = ( *tit )->renderPasses();
131  for ( auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
132  {
133  Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
134  cullFace->setMode( _qt3DcullingMode( symbol.cullingMode() ) );
135  ( *rpit )->addRenderState( cullFace );
136  }
137  }
138 
139  material->setAmbient( symbol.material().ambient() );
140  material->setDiffuse( symbol.material().diffuse() );
141  material->setSpecular( symbol.material().specular() );
142  material->setShininess( symbol.material().shininess() );
143  return material;
144 }
145 
146 QgsPolygon3DSymbolEntityNode::QgsPolygon3DSymbolEntityNode( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
147  : Qt3DCore::QEntity( parent )
148 {
149  addComponent( renderer( map, symbol, layer, req ) );
150 }
151 
152 Qt3DRender::QGeometryRenderer *QgsPolygon3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsPolygon3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
153 {
154  QgsPointXY origin( map.origin().x(), map.origin().y() );
155  QList<QgsPolygon *> polygons;
156  QList<QgsFeatureId> fids;
157  QList<float> extrusionHeightPerPolygon; // will stay empty if not needed per polygon
158 
159  QgsExpressionContext ctx( _expressionContext3D() );
160  ctx.setFields( layer->fields() );
161 
162  const QgsPropertyCollection &ddp = symbol.dataDefinedProperties();
163  bool hasDDHeight = ddp.isActive( QgsAbstract3DSymbol::PropertyHeight );
164  bool hasDDExtrusion = ddp.isActive( QgsAbstract3DSymbol::PropertyExtrusionHeight );
165 
166  QgsFeature f;
167  QgsFeatureIterator fi = layer->getFeatures( request );
168  while ( fi.nextFeature( f ) )
169  {
170  if ( f.geometry().isNull() )
171  continue;
172 
173  QgsGeometry geom = f.geometry();
174 
175  // segmentize curved geometries if necessary
176  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
177  geom = QgsGeometry( geom.constGet()->segmentize() );
178 
179  const QgsAbstractGeometry *g = geom.constGet();
180 
181  ctx.setFeature( f );
182  float height = symbol.height();
183  float extrusionHeight = symbol.extrusionHeight();
184  if ( hasDDHeight )
185  height = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyHeight, ctx, height );
186  if ( hasDDExtrusion )
187  extrusionHeight = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyExtrusionHeight, ctx, extrusionHeight );
188 
189  if ( const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
190  {
191  QgsPolygon *polyClone = poly->clone();
192  Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map );
193  polygons.append( polyClone );
194  fids.append( f.id() );
195  if ( hasDDExtrusion )
196  extrusionHeightPerPolygon.append( extrusionHeight );
197  }
198  else if ( const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
199  {
200  for ( int i = 0; i < mpoly->numGeometries(); ++i )
201  {
202  const QgsAbstractGeometry *g2 = mpoly->geometryN( i );
203  Q_ASSERT( QgsWkbTypes::flatType( g2->wkbType() ) == QgsWkbTypes::Polygon );
204  QgsPolygon *polyClone = static_cast< const QgsPolygon *>( g2 )->clone();
205  Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map );
206  polygons.append( polyClone );
207  fids.append( f.id() );
208  if ( hasDDExtrusion )
209  extrusionHeightPerPolygon.append( extrusionHeight );
210  }
211  }
212  else if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( g ) )
213  {
214  for ( int i = 0; i < gc->numGeometries(); ++i )
215  {
216  const QgsAbstractGeometry *g2 = gc->geometryN( i );
218  continue;
219  QgsPolygon *polyClone = static_cast< const QgsPolygon *>( g2 )->clone();
220  Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map );
221  polygons.append( polyClone );
222  fids.append( f.id() );
223  if ( hasDDExtrusion )
224  extrusionHeightPerPolygon.append( extrusionHeight );
225  }
226  }
227  else
228  qDebug() << "not a polygon";
229  }
230 
231  mGeometry = new QgsTessellatedPolygonGeometry;
232  mGeometry->setInvertNormals( symbol.invertNormals() );
233  mGeometry->setAddBackFaces( symbol.addBackFaces() );
234  mGeometry->setPolygons( polygons, fids, origin, symbol.extrusionHeight(), extrusionHeightPerPolygon );
235 
236  Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
237  renderer->setGeometry( mGeometry );
238 
239  return renderer;
240 }
241 
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
float shininess() const
Returns shininess of the surface.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
void setInvertNormals(bool invert)
Sets whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwi...
QgsPhongMaterialSettings material() const
Returns material used for shading of the symbol.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
A class to represent a 2D point.
Definition: qgspointxy.h:43
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
3 3D symbol that draws polygon geometries as planar polygons, optionally extruded (with added walls)...
CullingMode
Triangle culling mode.
Definition: qgs3dtypes.h:49
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
Extrusion height (zero means no extrusion)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
Will not render anything.
Definition: qgs3dtypes.h:54
Qgs3DTypes::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain)
3 Definition of the world
QColor selectionColor() const
Returns color used for selected features.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
bool addBackFaces() const
Returns whether also triangles facing the other side will be created.
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
Will render only front faces of triangles (recommended when input data are consistent) ...
Definition: qgs3dtypes.h:53
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QColor specular() const
Returns specular color component.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
Will render only back faces of triangles.
Definition: qgs3dtypes.h:52
Will render both front and back faces of triangles.
Definition: qgs3dtypes.h:51
bool invertNormals() const
Returns whether the normals of triangles will be inverted (useful for fixing clockwise / counter-cloc...
Geometry collection.
Qgs3DTypes::AltitudeBinding altitudeBinding() const
Returns method that determines how altitude is bound to individual vertices.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
float height() const
Returns height (altitude) of the symbol (in map units)
3 Class derived from Qt3DRender::QGeometry that represents polygons tessellated into 3D geometry...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
float extrusionHeight() const
Returns extrusion height (in map units)
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Abstract base class for all geometries.
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QColor ambient() const
Returns ambient color component.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double...
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
Multi polygon geometry collection.
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:744
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:411
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:42
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
static void clampAltitudes(QgsLineString *lineString, Qgs3DTypes::AltitudeClamping altClamp, Qgs3DTypes::AltitudeBinding altBind, const QgsPoint &centroid, float height, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
Definition: qgs3dutils.cpp:167
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsAbstract3DSymbol * clone() const override
Returns a new instance of the symbol with the same settings.
bool nextFeature(QgsFeature &f)
Polygon geometry type.
Definition: qgspolygon.h:31
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:565
void setAmbient(const QColor &ambient)
Sets ambient color component.
QColor diffuse() const
Returns diffuse color component.