QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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  mVertexBuffer = new Qt3DRender::QBuffer( this );
36 
37  const QgsTessellator tmpTess( 0, 0, mWithNormals, false, false, false, mAddTextureCoords );
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  mPositionAttribute->setByteOffset( 0 );
48  addAttribute( mPositionAttribute );
49 
50  if ( mWithNormals )
51  {
52  mNormalAttribute = new Qt3DRender::QAttribute( this );
53  mNormalAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName() );
54  mNormalAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
55  mNormalAttribute->setVertexSize( 3 );
56  mNormalAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
57  mNormalAttribute->setBuffer( mVertexBuffer );
58  mNormalAttribute->setByteStride( stride );
59  mNormalAttribute->setByteOffset( 3 * sizeof( float ) );
60  addAttribute( mNormalAttribute );
61  }
62  if ( mAddTextureCoords )
63  {
64  mTextureCoordsAttribute = new Qt3DRender::QAttribute( this );
65  mTextureCoordsAttribute->setName( Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName() );
66  mTextureCoordsAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
67  mTextureCoordsAttribute->setVertexSize( 2 );
68  mTextureCoordsAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
69  mTextureCoordsAttribute->setBuffer( mVertexBuffer );
70  mTextureCoordsAttribute->setByteStride( stride );
71  mTextureCoordsAttribute->setByteOffset( mWithNormals ? 6 * sizeof( float ) : 3 * sizeof( float ) );
72  addAttribute( mTextureCoordsAttribute );
73  }
74 }
75 
76 void QgsTessellatedPolygonGeometry::setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon )
77 {
78  Q_ASSERT( polygons.count() == featureIds.count() );
79  mTriangleIndexStartingIndices.reserve( polygons.count() );
80  mTriangleIndexFids.reserve( polygons.count() );
81 
82  QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals, mAddBackFaces, false, mAddTextureCoords );
83  for ( int i = 0; i < polygons.count(); ++i )
84  {
85  Q_ASSERT( tessellator.dataVerticesCount() % 3 == 0 );
86  const uint startingTriangleIndex = static_cast<uint>( tessellator.dataVerticesCount() / 3 );
87  mTriangleIndexStartingIndices.append( startingTriangleIndex );
88  mTriangleIndexFids.append( featureIds[i] );
89 
90  QgsPolygon *polygon = polygons.at( i );
91  const float extr = extrusionHeightPerPolygon.isEmpty() ? extrusionHeight : extrusionHeightPerPolygon.at( i );
92  tessellator.addPolygon( *polygon, extr );
93  }
94 
95  qDeleteAll( polygons );
96 
97  const QByteArray data( ( const char * )tessellator.data().constData(), tessellator.data().count() * sizeof( float ) );
98  const int nVerts = data.count() / tessellator.stride();
99 
100  mVertexBuffer->setData( data );
101  mPositionAttribute->setCount( nVerts );
102  if ( mNormalAttribute )
103  mNormalAttribute->setCount( nVerts );
104  if ( mAddTextureCoords )
105  mTextureCoordsAttribute->setCount( nVerts );
106 }
107 
108 void QgsTessellatedPolygonGeometry::setData( const QByteArray &vertexBufferData, int vertexCount, const QVector<QgsFeatureId> &triangleIndexFids, const QVector<uint> &triangleIndexStartingIndices )
109 {
110  mTriangleIndexStartingIndices = triangleIndexStartingIndices;
111  mTriangleIndexFids = triangleIndexFids;
112 
113  mVertexBuffer->setData( vertexBufferData );
114  mPositionAttribute->setCount( vertexCount );
115  if ( mNormalAttribute )
116  mNormalAttribute->setCount( vertexCount );
117  if ( mTextureCoordsAttribute )
118  mTextureCoordsAttribute->setCount( vertexCount );
119 }
120 
121 
122 // run binary search on a sorted array, return index i where data[i] <= x < data[i+1]
123 static int binary_search( uint v, const uint *data, int count )
124 {
125  int idx0 = 0;
126  int idx1 = count - 1;
127 
128  if ( v < data[0] || v >= data[count - 1] )
129  return -1; // not in the array
130 
131  while ( idx0 != idx1 )
132  {
133  const int idxPivot = ( idx0 + idx1 ) / 2;
134  const uint pivot = data[idxPivot];
135  if ( pivot <= v )
136  {
137  if ( data[idxPivot + 1] > v )
138  return idxPivot; // we're done!
139  else // continue searching values greater than the pivot
140  idx0 = idxPivot;
141  }
142  else // continue searching values lower than the pivot
143  idx1 = idxPivot;
144  }
145  return idx0;
146 }
147 
148 
150 {
151  const int i = binary_search( triangleIndex, mTriangleIndexStartingIndices.constData(), mTriangleIndexStartingIndices.count() );
152  return i != -1 ? mTriangleIndexFids[i] : FID_NULL;
153 }
qgspolygon.h
qgstessellatedpolygongeometry.h
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:33
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:470
QgsCurvePolygon::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:1013
QgsTessellatedPolygonGeometry::triangleIndexToFeatureId
QgsFeatureId triangleIndexToFeatureId(uint triangleIndex) const
Returns ID of the feature to which given triangle index belongs (used for picking).
Definition: qgstessellatedpolygongeometry.cpp:149
QgsTessellator::dataVerticesCount
int dataVerticesCount() const
Returns the number of vertices stored in the output data array.
Definition: qgstessellator.cpp:748
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:108
Qt3DRender
Definition: qgs3dmapscene.h:28
qgstessellator.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
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:40
QgsPointXY::x
double x
Definition: qgspointxy.h:62
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:76
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28