QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgstessellatedpolygongeometry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstessellatedpolygongeometry.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 
17 
18 #include <Qt3DRender/QAttribute>
19 #include <Qt3DRender/QBuffer>
20 #include <Qt3DRender/QBufferDataGenerator>
21 
22 #include "qgstessellator.h"
23 
24 #include "qgspoint.h"
25 #include "qgspolygon.h"
26 
27 
28 QgsTessellatedPolygonGeometry::QgsTessellatedPolygonGeometry( bool _withNormals, bool _invertNormals, bool _addBackFaces, bool _addTextureCoords, QNode *parent )
29  : Qt3DRender::QGeometry( parent ),
30  mWithNormals( _withNormals ),
31  mInvertNormals( _invertNormals ),
32  mAddBackFaces( _addBackFaces ),
33  mAddTextureCoords( _addTextureCoords )
34 {
35 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
36  mVertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this );
37 #else
38  mVertexBuffer = new Qt3DRender::QBuffer( this );
39 #endif
40 
41  QgsTessellator tmpTess( 0, 0, mWithNormals, false, false, false, mAddTextureCoords );
42  const int stride = tmpTess.stride();
43 
44  mPositionAttribute = new Qt3DRender::QAttribute( this );
45  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
46  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
47  mPositionAttribute->setVertexSize( 3 );
48  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
49  mPositionAttribute->setBuffer( mVertexBuffer );
50  mPositionAttribute->setByteStride( stride );
51  mPositionAttribute->setByteOffset( 0 );
52  addAttribute( mPositionAttribute );
53 
54  if ( mWithNormals )
55  {
56  mNormalAttribute = new Qt3DRender::QAttribute( this );
57  mNormalAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName() );
58  mNormalAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
59  mNormalAttribute->setVertexSize( 3 );
60  mNormalAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
61  mNormalAttribute->setBuffer( mVertexBuffer );
62  mNormalAttribute->setByteStride( stride );
63  mNormalAttribute->setByteOffset( 3 * sizeof( float ) );
64  addAttribute( mNormalAttribute );
65  }
66  if ( mAddTextureCoords )
67  {
68  mTextureCoordsAttribute = new Qt3DRender::QAttribute( this );
69  mTextureCoordsAttribute->setName( Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName() );
70  mTextureCoordsAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
71  mTextureCoordsAttribute->setVertexSize( 2 );
72  mTextureCoordsAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
73  mTextureCoordsAttribute->setBuffer( mVertexBuffer );
74  mTextureCoordsAttribute->setByteStride( stride );
75  mTextureCoordsAttribute->setByteOffset( mWithNormals ? 6 * sizeof( float ) : 3 * sizeof( float ) );
76  addAttribute( mTextureCoordsAttribute );
77  }
78 }
79 
80 void QgsTessellatedPolygonGeometry::setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon )
81 {
82  Q_ASSERT( polygons.count() == featureIds.count() );
83  mTriangleIndexStartingIndices.reserve( polygons.count() );
84  mTriangleIndexFids.reserve( polygons.count() );
85 
86  QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals, mAddBackFaces, false, mAddTextureCoords );
87  for ( int i = 0; i < polygons.count(); ++i )
88  {
89  Q_ASSERT( tessellator.dataVerticesCount() % 3 == 0 );
90  uint startingTriangleIndex = static_cast<uint>( tessellator.dataVerticesCount() / 3 );
91  mTriangleIndexStartingIndices.append( startingTriangleIndex );
92  mTriangleIndexFids.append( featureIds[i] );
93 
94  QgsPolygon *polygon = polygons.at( i );
95  float extr = extrusionHeightPerPolygon.isEmpty() ? extrusionHeight : extrusionHeightPerPolygon.at( i );
96  tessellator.addPolygon( *polygon, extr );
97  }
98 
99  qDeleteAll( polygons );
100 
101  QByteArray data( ( const char * )tessellator.data().constData(), tessellator.data().count() * sizeof( float ) );
102  int nVerts = data.count() / tessellator.stride();
103 
104  mVertexBuffer->setData( data );
105  mPositionAttribute->setCount( nVerts );
106  if ( mNormalAttribute )
107  mNormalAttribute->setCount( nVerts );
108  if ( mAddTextureCoords )
109  mTextureCoordsAttribute->setCount( nVerts );
110 }
111 
112 void QgsTessellatedPolygonGeometry::setData( const QByteArray &vertexBufferData, int vertexCount, const QVector<QgsFeatureId> &triangleIndexFids, const QVector<uint> &triangleIndexStartingIndices )
113 {
114  mTriangleIndexStartingIndices = triangleIndexStartingIndices;
115  mTriangleIndexFids = triangleIndexFids;
116 
117  mVertexBuffer->setData( vertexBufferData );
118  mPositionAttribute->setCount( vertexCount );
119  if ( mNormalAttribute )
120  mNormalAttribute->setCount( vertexCount );
121  if ( mTextureCoordsAttribute )
122  mTextureCoordsAttribute->setCount( vertexCount );
123 }
124 
125 
126 // run binary search on a sorted array, return index i where data[i] <= x < data[i+1]
127 static int binary_search( uint v, const uint *data, int count )
128 {
129  int idx0 = 0;
130  int idx1 = count - 1;
131 
132  if ( v < data[0] || v >= data[count - 1] )
133  return -1; // not in the array
134 
135  while ( idx0 != idx1 )
136  {
137  int idxPivot = ( idx0 + idx1 ) / 2;
138  uint pivot = data[idxPivot];
139  if ( pivot <= v )
140  {
141  if ( data[idxPivot + 1] > v )
142  return idxPivot; // we're done!
143  else // continue searching values greater than the pivot
144  idx0 = idxPivot;
145  }
146  else // continue searching values lower than the pivot
147  idx1 = idxPivot;
148  }
149  return idx0;
150 }
151 
152 
154 {
155  int i = binary_search( triangleIndex, mTriangleIndexStartingIndices.constData(), mTriangleIndexStartingIndices.count() );
156  return i != -1 ? mTriangleIndexFids[i] : FID_NULL;
157 }
qgspolygon.h
qgstessellatedpolygongeometry.h
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:34
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsTessellator::stride
int stride() const
Returns size of one vertex entry in bytes.
Definition: qgstessellator.h:73
FID_NULL
#define FID_NULL
Definition: qgsfeatureid.h:29
qgspoint.h
QgsTessellator::addPolygon
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array.
Definition: qgstessellator.cpp:528
QgsCurvePolygon::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:918
QgsTessellatedPolygonGeometry::triangleIndexToFeatureId
QgsFeatureId triangleIndexToFeatureId(uint triangleIndex) const
Returns ID of the feature to which given triangle index belongs (used for picking).
Definition: qgstessellatedpolygongeometry.cpp:153
QgsTessellator::dataVerticesCount
int dataVerticesCount() const
Returns the number of vertices stored in the output data array.
Definition: qgstessellator.cpp:813
QgsTessellatedPolygonGeometry::setData
void setData(const QByteArray &vertexBufferData, int vertexCount, const QVector< QgsFeatureId > &triangleIndexFids, const QVector< uint > &triangleIndexStartingIndices)
Initializes vertex buffer (and other members) from data that were already tessellated.
Definition: qgstessellatedpolygongeometry.cpp:112
Qt3DRender
Definition: qgs3dmapscene.h:27
qgstessellator.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsTessellatedPolygonGeometry::QgsTessellatedPolygonGeometry
QgsTessellatedPolygonGeometry(bool _withNormals=true, bool invertNormals=false, bool addBackFaces=false, bool addTextureCoords=false, QNode *parent=nullptr)
Constructor.
Definition: qgstessellatedpolygongeometry.cpp:28
QgsTessellator
Class that takes care of tessellation of polygons into triangles.
Definition: qgstessellator.h:41
QgsTessellator::data
QVector< float > data() const
Returns array of triangle vertex data.
Definition: qgstessellator.h:67
QgsTessellatedPolygonGeometry::setPolygons
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.
Definition: qgstessellatedpolygongeometry.cpp:80
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28