QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsline3dsymbol_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsline3dsymbol_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 "qgsline3dsymbol_p.h"
17 
18 #include "qgsline3dsymbol.h"
20 #include "qgs3dmapsettings.h"
21 //#include "qgsterraingenerator.h"
22 #include "qgs3dutils.h"
23 
24 #include "qgsvectorlayer.h"
25 #include "qgsmultilinestring.h"
26 #include "qgsmultipolygon.h"
27 #include "qgsgeos.h"
28 
29 #include <Qt3DRender/QAttribute>
30 #include <Qt3DRender/QBuffer>
31 
33 
34 QgsLine3DSymbolEntity::QgsLine3DSymbolEntity( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, Qt3DCore::QNode *parent )
35  : Qt3DCore::QEntity( parent )
36 {
37  addEntityForSelectedLines( map, layer, symbol );
38  addEntityForNotSelectedLines( map, layer, symbol );
39 }
40 
41 Qt3DExtras::QPhongMaterial *QgsLine3DSymbolEntity::material( const QgsLine3DSymbol &symbol ) const
42 {
43  Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial;
44 
45  material->setAmbient( symbol.material().ambient() );
46  material->setDiffuse( symbol.material().diffuse() );
47  material->setSpecular( symbol.material().specular() );
48  material->setShininess( symbol.material().shininess() );
49 
50  return material;
51 }
52 
53 void QgsLine3DSymbolEntity::addEntityForSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol )
54 {
55  // build the default material
56  Qt3DExtras::QPhongMaterial *mat = material( symbol );
57 
58  // update the material with selection colors
59  mat->setDiffuse( map.selectionColor() );
60  mat->setAmbient( map.selectionColor().darker() );
61 
62  // build the feature request to select features
64  req.setDestinationCrs( map.crs(), map.transformContext() );
65  req.setFilterFids( layer->selectedFeatureIds() );
66 
67  // build the entity
68  QgsLine3DSymbolEntityNode *entity = new QgsLine3DSymbolEntityNode( map, layer, symbol, req );
69  entity->addComponent( mat );
70  entity->setParent( this );
71 }
72 
73 void QgsLine3DSymbolEntity::addEntityForNotSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol )
74 {
75  // build the default material
76  Qt3DExtras::QPhongMaterial *mat = material( symbol );
77 
78  // build the feature request to select features
80  req.setDestinationCrs( map.crs(), map.transformContext() );
81 
82  QgsFeatureIds notSelected = layer->allFeatureIds();
83  notSelected.subtract( layer->selectedFeatureIds() );
84  req.setFilterFids( notSelected );
85 
86  // build the entity
87  QgsLine3DSymbolEntityNode *entity = new QgsLine3DSymbolEntityNode( map, layer, symbol, req );
88  entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral( "main" ) ); // temporary measure to distinguish between "selected" and "main"
89  entity->addComponent( mat );
90  entity->setParent( this );
91 }
92 
93 QgsLine3DSymbolEntityNode::QgsLine3DSymbolEntityNode( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
94  : Qt3DCore::QEntity( parent )
95 {
96  addComponent( symbol.renderAsSimpleLines() ? rendererSimple( map, symbol, layer, req ) : renderer( map, symbol, layer, req ) );
97 }
98 
99 Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
100 {
101  QgsPointXY origin( map.origin().x(), map.origin().y() );
102 
103  // TODO: configurable
104  int nSegments = 4;
107  double mitreLimit = 0;
108 
109  QList<QgsPolygon *> polygons;
110  QList<QgsFeatureId> fids;
111  QgsFeature f;
112  QgsFeatureIterator fi = layer->getFeatures( request );
113  while ( fi.nextFeature( f ) )
114  {
115  if ( f.geometry().isNull() )
116  continue;
117 
118  QgsGeometry geom = f.geometry();
119 
120  // segmentize curved geometries if necessary
121  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
122  geom = QgsGeometry( geom.constGet()->segmentize() );
123 
124  const QgsAbstractGeometry *g = geom.constGet();
125 
126  QgsGeos engine( g );
127  QgsAbstractGeometry *buffered = engine.buffer( symbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory
128 
129  if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::Polygon )
130  {
131  QgsPolygon *polyBuffered = static_cast<QgsPolygon *>( buffered );
132  Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map );
133  polygons.append( polyBuffered );
134  fids.append( f.id() );
135  }
136  else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::MultiPolygon )
137  {
138  QgsMultiPolygon *mpolyBuffered = static_cast<QgsMultiPolygon *>( buffered );
139  for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i )
140  {
141  QgsAbstractGeometry *partBuffered = mpolyBuffered->geometryN( i );
142  Q_ASSERT( QgsWkbTypes::flatType( partBuffered->wkbType() ) == QgsWkbTypes::Polygon );
143  QgsPolygon *polyBuffered = static_cast<QgsPolygon *>( partBuffered )->clone(); // need to clone individual geometry parts
144  Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map );
145  polygons.append( polyBuffered );
146  fids.append( f.id() );
147  }
148  delete buffered;
149  }
150  }
151 
152  mGeometry = new QgsTessellatedPolygonGeometry;
153  mGeometry->setPolygons( polygons, fids, origin, symbol.extrusionHeight() );
154 
155  Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
156  renderer->setGeometry( mGeometry );
157 
158  return renderer;
159 }
160 
161 
162 Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::rendererSimple( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
163 {
164  QVector<QVector3D> vertices;
165  vertices << QVector3D(); // the first index is invalid, we use it for primitive restart
166  QVector<unsigned int> indexes;
167 
168  QgsPoint centroid;
169  QgsPointXY origin( map.origin().x(), map.origin().y() );
170  QgsFeature f;
171  QgsFeatureIterator fi = layer->getFeatures( request );
172  while ( fi.nextFeature( f ) )
173  {
174  if ( f.geometry().isNull() )
175  continue;
176 
178  centroid = QgsPoint( f.geometry().centroid().asPoint() );
179 
180  QgsGeometry geom = f.geometry();
181  const QgsAbstractGeometry *g = geom.constGet();
182  if ( const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( g ) )
183  {
184  for ( int i = 0; i < ls->vertexCount(); ++i )
185  {
186  QgsPoint p = ls->pointN( i );
187  float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map );
188  vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) );
189  indexes << vertices.count() - 1;
190  }
191  }
192  else if ( const QgsMultiLineString *mls = qgsgeometry_cast<const QgsMultiLineString *>( g ) )
193  {
194  for ( int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom )
195  {
196  const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( mls->geometryN( nGeom ) );
197  for ( int i = 0; i < ls->vertexCount(); ++i )
198  {
199  QgsPoint p = ls->pointN( i );
200  float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map );
201  vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) );
202  indexes << vertices.count() - 1;
203  }
204  indexes << 0; // add primitive restart
205  }
206  }
207 
208  indexes << 0; // add primitive restart
209  }
210 
211  QByteArray vertexBufferData;
212  vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) );
213  float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
214  int idx = 0;
215  for ( const auto &v : qgis::as_const( vertices ) )
216  {
217  rawVertexArray[idx++] = v.x();
218  rawVertexArray[idx++] = v.y();
219  rawVertexArray[idx++] = v.z();
220  }
221 
222  QByteArray indexBufferData;
223  indexBufferData.resize( indexes.size() * sizeof( int ) );
224  unsigned int *rawIndexArray = reinterpret_cast<unsigned int *>( indexBufferData.data() );
225  idx = 0;
226  for ( unsigned int indexVal : qgis::as_const( indexes ) )
227  {
228  rawIndexArray[idx++] = indexVal;
229  }
230 
231  Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this );
232  vertexBuffer->setData( vertexBufferData );
233 
234  Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, this );
235  indexBuffer->setData( indexBufferData );
236 
237  Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute( this );
238  positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
239  positionAttribute->setBuffer( vertexBuffer );
240  positionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
241  positionAttribute->setVertexSize( 3 );
242  positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
243 
244  Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute( this );
245  indexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute );
246  indexAttribute->setBuffer( indexBuffer );
247  indexAttribute->setVertexBaseType( Qt3DRender::QAttribute::UnsignedInt );
248 
249  Qt3DRender::QGeometry *geom = new Qt3DRender::QGeometry;
250  geom->addAttribute( positionAttribute );
251  geom->addAttribute( indexAttribute );
252 
253  Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
254  renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStrip );
255  renderer->setGeometry( geom );
256  renderer->setVertexCount( vertices.count() );
257  renderer->setPrimitiveRestartEnabled( true );
258  renderer->setRestartIndexValue( 0 );
259  return renderer;
260 }
261 
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.
double y
Definition: qgspoint.h:42
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
float height() const
Returns height (altitude) of the symbol (in map units)
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
void setPolygons(const QList< QgsPolygon * > &polygons, const QList< QgsFeatureId > &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList< float > &extrusionHeightPerPolygon=QList< float >())
Initializes vertex buffer from given polygons. Takes ownership of passed polygon geometries.
float width() const
Returns width of the line symbol (in map units)
A class to represent a 2D point.
Definition: qgspointxy.h:43
Qgs3DTypes::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain)
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Multi line string geometry collection.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
bool renderAsSimpleLines() const
Returns whether the renderer will render data with simple lines (otherwise it uses buffer) ...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
EndCapStyle
End cap styles for buffers.
Definition: qgsgeometry.h:1038
3 Definition of the world
QColor selectionColor() const
Returns color used for selected features.
QgsPhongMaterialSettings material() const
Returns material used for shading of the symbol.
float extrusionHeight() const
Returns extrusion height (in map units)
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsAbstract3DSymbol * clone() const override
Returns a new instance of the symbol with the same settings.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
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.
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurve.cpp:151
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
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)...
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
static float clampAltitude(const QgsPoint &p, Qgs3DTypes::AltitudeClamping altClamp, Qgs3DTypes::AltitudeBinding altBind, float height, const QgsPoint &centroid, const Qgs3DMapSettings &map)
Clamps altitude of a vertex according to the settings, returns Z value.
Definition: qgs3dutils.cpp:152
3 3D symbol that draws linestring geometries as planar polygons (created from lines using a buffer wi...
int numGeometries() const
Returns the number of geometries within the collection.
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Abstract base class for all geometries.
Does vector analysis using the geos library and handles import, export, exception handling*...
Definition: qgsgeos.h:103
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
Qgs3DTypes::AltitudeBinding altitudeBinding() const
Returns method that determines how altitude is bound to individual vertices.
Use rounded joins.
Definition: qgsgeometry.h:1049
QColor ambient() const
Returns ambient color component.
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)
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
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
bool nextFeature(QgsFeature &f)
Polygon geometry type.
Definition: qgspolygon.h:31
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1047
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
Clamp just centroid of feature.
Definition: qgs3dtypes.h:45
void setAmbient(const QColor &ambient)
Sets ambient color component.
QColor diffuse() const
Returns diffuse color component.
double x
Definition: qgspoint.h:41