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