QGIS API Documentation  3.0.2-Girona (307d082)
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->addComponent( mat );
105  entity->addComponent( tform );
106  entity->setParent( this );
107 }
108 
109 
110 Qt3DExtras::QPhongMaterial *QgsPolygon3DSymbolEntity::material( const QgsPolygon3DSymbol &symbol ) const
111 {
112  Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial;
113 
114  // front/back side culling
115  auto techniques = material->effect()->techniques();
116  for ( auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
117  {
118  auto renderPasses = ( *tit )->renderPasses();
119  for ( auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
120  {
121  Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
122  cullFace->setMode( symbol.cullingMode() );
123  ( *rpit )->addRenderState( cullFace );
124  }
125  }
126 
127  material->setAmbient( symbol.material().ambient() );
128  material->setDiffuse( symbol.material().diffuse() );
129  material->setSpecular( symbol.material().specular() );
130  material->setShininess( symbol.material().shininess() );
131  return material;
132 }
133 
134 QgsPolygon3DSymbolEntityNode::QgsPolygon3DSymbolEntityNode( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
135  : Qt3DCore::QEntity( parent )
136 {
137  addComponent( renderer( map, symbol, layer, req ) );
138 }
139 
140 Qt3DRender::QGeometryRenderer *QgsPolygon3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsPolygon3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
141 {
142  QgsPointXY origin( map.origin().x(), map.origin().y() );
143  QList<QgsPolygon *> polygons;
144  QList<float> extrusionHeightPerPolygon; // will stay empty if not needed per polygon
145 
146  QgsExpressionContext ctx( _expressionContext3D() );
147  ctx.setFields( layer->fields() );
148 
149  const QgsPropertyCollection &ddp = symbol.dataDefinedProperties();
150  bool hasDDHeight = ddp.isActive( QgsAbstract3DSymbol::PropertyHeight );
151  bool hasDDExtrusion = ddp.isActive( QgsAbstract3DSymbol::PropertyExtrusionHeight );
152 
153  QgsFeature f;
154  QgsFeatureIterator fi = layer->getFeatures( request );
155  while ( fi.nextFeature( f ) )
156  {
157  if ( f.geometry().isNull() )
158  continue;
159 
160  QgsGeometry geom = f.geometry();
161 
162  // segmentize curved geometries if necessary
163  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
164  geom = QgsGeometry( geom.constGet()->segmentize() );
165 
166  const QgsAbstractGeometry *g = geom.constGet();
167 
168  ctx.setFeature( f );
169  float height = symbol.height();
170  float extrusionHeight = symbol.extrusionHeight();
171  if ( hasDDHeight )
172  height = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyHeight, ctx, height );
173  if ( hasDDExtrusion )
174  extrusionHeight = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyExtrusionHeight, ctx, extrusionHeight );
175 
176  if ( const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
177  {
178  QgsPolygon *polyClone = poly->clone();
179  Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map );
180  polygons.append( polyClone );
181  if ( hasDDExtrusion )
182  extrusionHeightPerPolygon.append( extrusionHeight );
183  }
184  else if ( const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
185  {
186  for ( int i = 0; i < mpoly->numGeometries(); ++i )
187  {
188  const QgsAbstractGeometry *g2 = mpoly->geometryN( i );
189  Q_ASSERT( QgsWkbTypes::flatType( g2->wkbType() ) == QgsWkbTypes::Polygon );
190  QgsPolygon *polyClone = static_cast< const QgsPolygon *>( g2 )->clone();
191  Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map );
192  polygons.append( polyClone );
193  if ( hasDDExtrusion )
194  extrusionHeightPerPolygon.append( extrusionHeight );
195  }
196  }
197  else
198  qDebug() << "not a polygon";
199  }
200 
201  mGeometry = new QgsTessellatedPolygonGeometry;
202  mGeometry->setInvertNormals( symbol.invertNormals() );
203  mGeometry->setPolygons( polygons, origin, symbol.extrusionHeight(), extrusionHeightPerPolygon );
204 
205  Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
206  renderer->setGeometry( mGeometry );
207 
208  return renderer;
209 }
210 
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
float height() const
Returns height (altitude) of the symbol (in map units)
Wrapper for iterator of features from vector data provider or vector layer.
float shininess() const
Returns shininess of the surface.
QColor selectionColor() const
Returns color used for selected features.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
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...
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...
static void clampAltitudes(QgsLineString *lineString, AltitudeClamping altClamp, AltitudeBinding altBind, const QgsPoint &centroid, float height, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
Definition: qgs3dutils.cpp:110
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
QColor specular() const
Returns specular color component.
A class to represent a 2D point.
Definition: qgspointxy.h:43
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)...
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:111
AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain)
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:62
QgsPhongMaterialSettings material() const
Returns material used for shading of the symbol.
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:44
3 Definition of the world
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
const QgsFeatureIds & selectedFeatureIds() const
Return reference to identifiers of selected features.
QgsFields fields() const override
Returns the list of fields of this layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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)...
Qt3DRender::QCullFace::CullingMode cullingMode() const
Returns front/back culling mode.
Abstract base class for all geometries.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
bool invertNormals() const
Returns whether the normals of triangles will be inverted (useful for fixing clockwise / counter-cloc...
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
AltitudeBinding altitudeBinding() const
Returns method that determines how altitude is bound to individual vertices.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set 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:606
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:42
QColor ambient() const
Returns ambient color component.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QColor diffuse() const
Returns diffuse color component.
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.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
void setAmbient(const QColor &ambient)
Sets ambient color component.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:42
float extrusionHeight() const
Returns extrusion height (in map units)