QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 }
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
A class to represent a 2D point.
Definition: qgspointxy.h:44
double y
Definition: qgspointxy.h:48
Q_GADGET double x
Definition: qgspointxy.h:47
Polygon geometry type.
Definition: qgspolygon.h:34
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.
QgsFeatureId triangleIndexToFeatureId(uint triangleIndex) const
Returns ID of the feature to which given triangle index belongs (used for picking).
QgsTessellatedPolygonGeometry(bool _withNormals=true, bool invertNormals=false, bool addBackFaces=false, bool addTextureCoords=false, QNode *parent=nullptr)
Constructor.
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.
Class that takes care of tessellation of polygons into triangles.
QVector< float > data() const
Returns array of triangle vertex data.
int stride() const
Returns size of one vertex entry in bytes.
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array.
int dataVerticesCount() const
Returns the number of vertices stored in the output data array.
#define FID_NULL
Definition: qgsfeatureid.h:29
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28