QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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 
29  : Qt3DRender::QGeometry( parent )
30 {
31 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
32  mVertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this );
33 #else
34  mVertexBuffer = new Qt3DRender::QBuffer( this );
35 #endif
36 
37  QgsTessellator tmpTess( 0, 0, mWithNormals );
38  const int stride = tmpTess.stride();
39 
40  mPositionAttribute = new Qt3DRender::QAttribute( this );
41  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
42  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
43  mPositionAttribute->setVertexSize( 3 );
44  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
45  mPositionAttribute->setBuffer( mVertexBuffer );
46  mPositionAttribute->setByteStride( stride );
47  addAttribute( mPositionAttribute );
48 
49  if ( mWithNormals )
50  {
51  mNormalAttribute = new Qt3DRender::QAttribute( this );
52  mNormalAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName() );
53  mNormalAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
54  mNormalAttribute->setVertexSize( 3 );
55  mNormalAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
56  mNormalAttribute->setBuffer( mVertexBuffer );
57  mNormalAttribute->setByteStride( stride );
58  mNormalAttribute->setByteOffset( 3 * sizeof( float ) );
59  addAttribute( mNormalAttribute );
60  }
61 }
62 
63 void QgsTessellatedPolygonGeometry::setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon )
64 {
65  Q_ASSERT( polygons.count() == featureIds.count() );
66  mTriangleIndexStartingIndices.reserve( polygons.count() );
67  mTriangleIndexFids.reserve( polygons.count() );
68 
69  QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals, mAddBackFaces );
70  for ( int i = 0; i < polygons.count(); ++i )
71  {
72  Q_ASSERT( tessellator.dataVerticesCount() % 3 == 0 );
73  uint startingTriangleIndex = static_cast<uint>( tessellator.dataVerticesCount() / 3 );
74  mTriangleIndexStartingIndices.append( startingTriangleIndex );
75  mTriangleIndexFids.append( featureIds[i] );
76 
77  QgsPolygon *polygon = polygons.at( i );
78  float extr = extrusionHeightPerPolygon.isEmpty() ? extrusionHeight : extrusionHeightPerPolygon.at( i );
79  tessellator.addPolygon( *polygon, extr );
80  }
81 
82  qDeleteAll( polygons );
83 
84  QByteArray data( ( const char * )tessellator.data().constData(), tessellator.data().count() * sizeof( float ) );
85  int nVerts = data.count() / tessellator.stride();
86 
87  mVertexBuffer->setData( data );
88  mPositionAttribute->setCount( nVerts );
89  if ( mNormalAttribute )
90  mNormalAttribute->setCount( nVerts );
91 }
92 
93 void QgsTessellatedPolygonGeometry::setData( const QByteArray &vertexBufferData, int vertexCount, const QVector<QgsFeatureId> &triangleIndexFids, const QVector<uint> &triangleIndexStartingIndices )
94 {
95  mTriangleIndexStartingIndices = triangleIndexStartingIndices;
96  mTriangleIndexFids = triangleIndexFids;
97 
98  mVertexBuffer->setData( vertexBufferData );
99  mPositionAttribute->setCount( vertexCount );
100  if ( mNormalAttribute )
101  mNormalAttribute->setCount( vertexCount );
102 }
103 
104 
105 // run binary search on a sorted array, return index i where data[i] <= x < data[i+1]
106 static int binary_search( uint v, const uint *data, int count )
107 {
108  int idx0 = 0;
109  int idx1 = count - 1;
110 
111  if ( v < data[0] || v >= data[count - 1] )
112  return -1; // not in the array
113 
114  while ( idx0 != idx1 )
115  {
116  int idxPivot = ( idx0 + idx1 ) / 2;
117  uint pivot = data[idxPivot];
118  if ( pivot <= v )
119  {
120  if ( data[idxPivot + 1] > v )
121  return idxPivot; // we're done!
122  else // continue searching values greater than the pivot
123  idx0 = idxPivot;
124  }
125  else // continue searching values lower than the pivot
126  idx1 = idxPivot;
127  }
128  return idx0;
129 }
130 
131 
133 {
134  int i = binary_search( triangleIndex, mTriangleIndexStartingIndices.constData(), mTriangleIndexStartingIndices.count() );
135  return i != -1 ? mTriangleIndexFids[i] : FID_NULL;
136 }
QgsFeatureId triangleIndexToFeatureId(uint triangleIndex) const
Returns ID of the feature to which given triangle index belongs (used for picking).
#define FID_NULL
Definition: qgsfeatureid.h:26
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
int stride() const
Returns size of one vertex entry in bytes.
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.
Class that takes care of tessellation of polygons into triangles.
double x
Definition: qgspointxy.h:47
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.
Polygon geometry type.
Definition: qgspolygon.h:31
QgsTessellatedPolygonGeometry(QNode *parent=nullptr)
Constructor.
bool isEmpty() const override
Returns true if the geometry is empty.