QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
18#include "qgsmessagelog.h"
19
20#include <QMatrix4x4>
21
22#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
23#include <Qt3DRender/QAttribute>
24#include <Qt3DRender/QBuffer>
25typedef Qt3DRender::QAttribute Qt3DQAttribute;
26typedef Qt3DRender::QBuffer Qt3DQBuffer;
27#else
28#include <Qt3DCore/QAttribute>
29#include <Qt3DCore/QBuffer>
30typedef Qt3DCore::QAttribute Qt3DQAttribute;
31typedef Qt3DCore::QBuffer Qt3DQBuffer;
32#endif
33
34#include "qgstessellator.h"
35#include "qgspolygon.h"
36
37QgsTessellatedPolygonGeometry::QgsTessellatedPolygonGeometry( bool _withNormals, bool _invertNormals, bool _addBackFaces, bool _addTextureCoords, QNode *parent )
38 : QGeometry( parent )
39 , mWithNormals( _withNormals )
40 , mInvertNormals( _invertNormals )
41 , mAddBackFaces( _addBackFaces )
42 , mAddTextureCoords( _addTextureCoords )
43{
44 mVertexBuffer = new Qt3DQBuffer( this );
45
46 const QgsTessellator tmpTess( 0, 0, mWithNormals, false, false, false, mAddTextureCoords );
47 const int stride = tmpTess.stride();
48
49 mPositionAttribute = new Qt3DQAttribute( this );
50 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
51 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
52 mPositionAttribute->setVertexSize( 3 );
53 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
54 mPositionAttribute->setBuffer( mVertexBuffer );
55 mPositionAttribute->setByteStride( stride );
56 mPositionAttribute->setByteOffset( 0 );
57 addAttribute( mPositionAttribute );
58
59 if ( mWithNormals )
60 {
61 mNormalAttribute = new Qt3DQAttribute( this );
62 mNormalAttribute->setName( Qt3DQAttribute::defaultNormalAttributeName() );
63 mNormalAttribute->setVertexBaseType( Qt3DQAttribute::Float );
64 mNormalAttribute->setVertexSize( 3 );
65 mNormalAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
66 mNormalAttribute->setBuffer( mVertexBuffer );
67 mNormalAttribute->setByteStride( stride );
68 mNormalAttribute->setByteOffset( 3 * sizeof( float ) );
69 addAttribute( mNormalAttribute );
70 }
71 if ( mAddTextureCoords )
72 {
73 mTextureCoordsAttribute = new Qt3DQAttribute( this );
74 mTextureCoordsAttribute->setName( Qt3DQAttribute::defaultTextureCoordinateAttributeName() );
75 mTextureCoordsAttribute->setVertexBaseType( Qt3DQAttribute::Float );
76 mTextureCoordsAttribute->setVertexSize( 2 );
77 mTextureCoordsAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
78 mTextureCoordsAttribute->setBuffer( mVertexBuffer );
79 mTextureCoordsAttribute->setByteStride( stride );
80 mTextureCoordsAttribute->setByteOffset( mWithNormals ? 6 * sizeof( float ) : 3 * sizeof( float ) );
81 addAttribute( mTextureCoordsAttribute );
82 }
83}
84
85void QgsTessellatedPolygonGeometry::setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon )
86{
87 Q_ASSERT( polygons.count() == featureIds.count() );
88 mTriangleIndexStartingIndices.reserve( polygons.count() );
89 mTriangleIndexFids.reserve( polygons.count() );
90
91 QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals, mAddBackFaces, false, mAddTextureCoords );
92 for ( int i = 0; i < polygons.count(); ++i )
93 {
94 Q_ASSERT( tessellator.dataVerticesCount() % 3 == 0 );
95 const uint startingTriangleIndex = static_cast<uint>( tessellator.dataVerticesCount() / 3 );
96 mTriangleIndexStartingIndices.append( startingTriangleIndex );
97 mTriangleIndexFids.append( featureIds[i] );
98
99 QgsPolygon *polygon = polygons.at( i );
100 const float extr = extrusionHeightPerPolygon.isEmpty() ? extrusionHeight : extrusionHeightPerPolygon.at( i );
101 tessellator.addPolygon( *polygon, extr );
102 }
103 if ( !tessellator.error().isEmpty() )
104 {
105 QgsMessageLog::logMessage( tessellator.error(), QObject::tr( "3D" ) );
106 }
107
108 qDeleteAll( polygons );
109
110 const QByteArray data( ( const char * )tessellator.data().constData(), tessellator.data().count() * sizeof( float ) );
111 const int nVerts = data.count() / tessellator.stride();
112
113 mVertexBuffer->setData( data );
114 mPositionAttribute->setCount( nVerts );
115 if ( mNormalAttribute )
116 mNormalAttribute->setCount( nVerts );
117 if ( mAddTextureCoords )
118 mTextureCoordsAttribute->setCount( nVerts );
119}
120
121void QgsTessellatedPolygonGeometry::setData( const QByteArray &vertexBufferData, int vertexCount, const QVector<QgsFeatureId> &triangleIndexFids, const QVector<uint> &triangleIndexStartingIndices )
122{
123 mTriangleIndexStartingIndices = triangleIndexStartingIndices;
124 mTriangleIndexFids = triangleIndexFids;
125
126 mVertexBuffer->setData( vertexBufferData );
127 mPositionAttribute->setCount( vertexCount );
128 if ( mNormalAttribute )
129 mNormalAttribute->setCount( vertexCount );
130 if ( mTextureCoordsAttribute )
131 mTextureCoordsAttribute->setCount( vertexCount );
132}
133
134// run binary search on a sorted array, return index i where data[i] <= v < data[i+1]
135static int binary_search( uint v, const uint *data, int count )
136{
137 int idx0 = 0;
138 int idx1 = count - 1;
139
140 if ( v < data[0] )
141 return -1; // not in the array
142
143 if ( v >= data[count - 1] )
144 return count - 1; // for larger values the last bin is returned
145
146 while ( idx0 != idx1 )
147 {
148 const int idxPivot = ( idx0 + idx1 ) / 2;
149 const uint pivot = data[idxPivot];
150 if ( pivot <= v )
151 {
152 if ( data[idxPivot + 1] > v )
153 return idxPivot; // we're done!
154 else // continue searching values greater than the pivot
155 idx0 = idxPivot;
156 }
157 else // continue searching values lower than the pivot
158 idx1 = idxPivot;
159 }
160 return idx0;
161}
162
163
165{
166 const int i = binary_search( triangleIndex, mTriangleIndexStartingIndices.constData(), mTriangleIndexStartingIndices.count() );
167 return i != -1 ? mTriangleIndexFids[i] : FID_NULL;
168}
bool isEmpty() const override
Returns true if the geometry is empty.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
A class to represent a 2D point.
Definition: qgspointxy.h:60
double y
Definition: qgspointxy.h:64
Q_GADGET double x
Definition: qgspointxy.h:63
Polygon geometry type.
Definition: qgspolygon.h:33
QVector< QgsFeatureId > featureIds() const
Returns included feature ids.
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.
QVector< uint > triangleIndexStartingIndices() const
Returns triangle index for features. For a feature featureIds()[i], matching triangles start at trian...
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.
QString error() const
Returns a descriptive error string if the tessellation failed.
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
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer