QGIS API Documentation 4.3.0-Master (3b7b3208a79)
Loading...
Searching...
No Matches
qgslinevertexdata_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslinevertexdata_p.cpp
3 --------------------------------------
4 Date : Apr 2019
5 Copyright : (C) 2019 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
16#include "qgslinevertexdata_p.h"
17
18#include "qgs3dutils.h"
19#include "qgslinematerial_p.h"
20#include "qgslinestring.h"
21#include "qgsmaterial.h"
23
24#include <QString>
25#include <Qt3DCore/QAttribute>
26#include <Qt3DCore/QBuffer>
27#include <Qt3DCore/QEntity>
28#include <Qt3DCore/QGeometry>
29#include <Qt3DRender/QGeometryRenderer>
30
31using namespace Qt::StringLiterals;
32
34
35static QByteArray toByteArray( const QVector<QVector3D> &points )
36{
37 QByteArray data;
38 data.resize( points.size() * 3 * sizeof( float ) );
39 float *raw = reinterpret_cast<float *>( data.data() );
40 int idx = 0;
41 for ( const QVector3D &p : points )
42 {
43 raw[idx++] = p.x();
44 raw[idx++] = p.y();
45 raw[idx++] = p.z();
46 }
47 return data;
48}
49
50void QgsLineVertexData::init( Qgis::AltitudeClamping clamping, Qgis::AltitudeBinding binding, float height, const Qgs3DRenderContext &context, const QgsVector3D &chunkOrigin )
51{
52 altClamping = clamping;
53 altBinding = binding;
54 baseHeight = height;
55 renderContext = context;
56 origin = chunkOrigin;
57}
58
59void QgsLineVertexData::addLineString( const QgsLineString &lineString, float extraHeightOffset, bool closePolygon )
60{
61 const int inVertexCount = lineString.vertexCount();
62 if ( inVertexCount == 0 )
63 return;
64
65 QgsPoint centroid;
66 switch ( altBinding )
67 {
69 break;
71 centroid = lineString.centroid();
72 break;
73 }
74
75 QVector<double> xs( inVertexCount );
76 QVector<double> ys( inVertexCount );
77 QVector<double> zs( inVertexCount );
78 for ( int i = 0; i < inVertexCount; ++i )
79 {
80 const QgsPoint p = lineString.pointN( i );
81 double z;
82 if ( geocentricCoordinates )
83 {
84 // TODO: implement altitude clamping when dealing with geocentric coordinates
85 // where Z coordinate is not altitude and can't be used directly...
86 z = p.z();
87 }
88 else
89 {
90 z = Qgs3DUtils::clampAltitude( p, altClamping, altBinding, baseHeight + extraHeightOffset, centroid, renderContext );
91 }
92
93 xs[i] = p.x() - origin.x();
94 ys[i] = p.y() - origin.y();
95 zs[i] = z - origin.z();
96 }
97
98 QgsLineString line( xs, ys, zs );
99 line.removeDuplicateNodes( 4 * std::numeric_limits<double>::epsilon(), true );
100
101 int vertexCount = line.vertexCount();
102 if ( vertexCount == 0 )
103 return;
104
105 QVector<QVector3D> points;
106 points.reserve( vertexCount );
107 for ( int i = 0; i < vertexCount; ++i )
108 points << QVector3D( static_cast<float>( line.xAt( i ) ), static_cast<float>( line.yAt( i ) ), static_cast<float>( line.zAt( i ) ) );
109
110 const QVector3D first = points.constFirst();
111 vertices << first;
112 QVector3D prevPrev = first;
113 QVector3D prev = first;
114 bool havePrevPrev = false;
115 for ( int i = 1; i < vertexCount; ++i )
116 {
117 const QVector3D curr = points.at( i );
118 pointsA << prev;
119 pointsB << curr;
120 vertices << curr;
121
122 if ( i == 1 )
123 pointsPrev << ( closePolygon ? points.constLast() : prev + ( prev - curr ) );
124 else
125 pointsPrev << prevPrev;
126
127 if ( i == vertexCount - 1 )
128 pointsNext << ( closePolygon ? first : curr + ( curr - prev ) );
129 else
130 pointsNext << points.at( i + 1 );
131
132 if ( havePrevPrev )
133 {
134 joinPointA << prevPrev;
135 joinPointB << prev;
136 joinPointC << curr;
137 }
138
139 prevPrev = prev;
140 prev = curr;
141 havePrevPrev = true;
142 }
143
144 if ( closePolygon && vertexCount >= 2 )
145 {
146 pointsA << prev;
147 pointsB << first;
148 pointsPrev << prevPrev;
149 pointsNext << points.at( 1 );
150
151 if ( vertexCount >= 3 )
152 {
153 joinPointA << prevPrev;
154 joinPointB << prev;
155 joinPointC << first;
156
157 joinPointA << prev;
158 joinPointB << first;
159 joinPointC << points.at( 1 );
160 }
161 }
162}
163
164void QgsLineVertexData::addVerticalLines( const QgsLineString &lineString, float verticalLength, float extraHeightOffset )
165{
166 QgsPoint centroid;
167 switch ( altBinding )
168 {
170 break;
172 centroid = lineString.centroid();
173 break;
174 }
175
176 for ( int i = 0; i < lineString.vertexCount(); ++i )
177 {
178 const QgsPoint p = lineString.pointN( i );
179 const float z = Qgs3DUtils::clampAltitude( p, altClamping, altBinding, baseHeight + extraHeightOffset, centroid, renderContext );
180 const float x = static_cast<float>( p.x() - origin.x() );
181 const float y = static_cast<float>( p.y() - origin.y() );
182 const QVector3D a( x, y, z );
183 const QVector3D b( x, y, z + verticalLength );
184 pointsA << a;
185 pointsB << b;
186 pointsPrev << a + ( a - b );
187 pointsNext << b + ( b - a );
188 }
189}
190
191QByteArray QgsLineVertexData::createPointABuffer() const
192{
193 return toByteArray( pointsA );
194}
195
196QByteArray QgsLineVertexData::createPointBBuffer() const
197{
198 return toByteArray( pointsB );
199}
200
201QByteArray QgsLineVertexData::createPointPrevBuffer() const
202{
203 return toByteArray( pointsPrev );
204}
205
206QByteArray QgsLineVertexData::createPointNextBuffer() const
207{
208 return toByteArray( pointsNext );
209}
210
211QByteArray QgsLineVertexData::createJoinPointABuffer() const
212{
213 return toByteArray( joinPointA );
214}
215
216QByteArray QgsLineVertexData::createJoinPointBBuffer() const
217{
218 return toByteArray( joinPointB );
219}
220
221QByteArray QgsLineVertexData::createJoinPointCBuffer() const
222{
223 return toByteArray( joinPointC );
224}
225
226Qt3DCore::QGeometry *QgsLineVertexData::createGeometry( Qt3DCore::QNode *parent )
227{
228 Q_ASSERT( pointsA.size() == pointsB.size() );
229 Q_ASSERT( pointsA.size() == pointsPrev.size() );
230 Q_ASSERT( pointsA.size() == pointsNext.size() );
231
232 static constexpr float quadVertices[] = {
233 0.0f,
234 -0.5f,
235 1.0f,
236 -0.5f,
237 1.0f,
238 0.5f,
239 0.0f,
240 -0.5f,
241 1.0f,
242 0.5f,
243 0.0f,
244 0.5f,
245 };
246
247 Qt3DCore::QBuffer *quadBuffer = new Qt3DCore::QBuffer( parent );
248 quadBuffer->setData( QByteArray( reinterpret_cast<const char *>( quadVertices ), sizeof( quadVertices ) ) );
249
250 Qt3DCore::QAttribute *positionAttribute = new Qt3DCore::QAttribute( parent );
251 positionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
252 positionAttribute->setBuffer( quadBuffer );
253 positionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
254 positionAttribute->setVertexSize( 2 );
255 positionAttribute->setByteStride( 2 * sizeof( float ) );
256 positionAttribute->setByteOffset( 0 );
257 positionAttribute->setCount( 6 );
258 positionAttribute->setName( Qt3DCore::QAttribute::defaultPositionAttributeName() );
259
260 Qt3DCore::QBuffer *pointABuffer = new Qt3DCore::QBuffer( parent );
261 pointABuffer->setData( createPointABuffer() );
262
263 Qt3DCore::QAttribute *pointAAttribute = new Qt3DCore::QAttribute( parent );
264 pointAAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
265 pointAAttribute->setBuffer( pointABuffer );
266 pointAAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
267 pointAAttribute->setVertexSize( 3 );
268 pointAAttribute->setByteStride( 3 * sizeof( float ) );
269 pointAAttribute->setByteOffset( 0 );
270 pointAAttribute->setCount( pointsA.size() );
271 pointAAttribute->setDivisor( 1 );
272 pointAAttribute->setName( u"pointA"_s );
273
274 Qt3DCore::QBuffer *pointBBuffer = new Qt3DCore::QBuffer( parent );
275 pointBBuffer->setData( createPointBBuffer() );
276
277 Qt3DCore::QAttribute *pointBAttribute = new Qt3DCore::QAttribute( parent );
278 pointBAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
279 pointBAttribute->setBuffer( pointBBuffer );
280 pointBAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
281 pointBAttribute->setVertexSize( 3 );
282 pointBAttribute->setByteStride( 3 * sizeof( float ) );
283 pointBAttribute->setByteOffset( 0 );
284 pointBAttribute->setCount( pointsB.size() );
285 pointBAttribute->setDivisor( 1 );
286 pointBAttribute->setName( u"pointB"_s );
287
288 Qt3DCore::QBuffer *pointPrevBuffer = new Qt3DCore::QBuffer( parent );
289 pointPrevBuffer->setData( createPointPrevBuffer() );
290
291 Qt3DCore::QAttribute *pointPrevAttribute = new Qt3DCore::QAttribute( parent );
292 pointPrevAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
293 pointPrevAttribute->setBuffer( pointPrevBuffer );
294 pointPrevAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
295 pointPrevAttribute->setVertexSize( 3 );
296 pointPrevAttribute->setByteStride( 3 * sizeof( float ) );
297 pointPrevAttribute->setByteOffset( 0 );
298 pointPrevAttribute->setCount( pointsPrev.size() );
299 pointPrevAttribute->setDivisor( 1 );
300 pointPrevAttribute->setName( u"pointPrev"_s );
301
302 Qt3DCore::QBuffer *pointNextBuffer = new Qt3DCore::QBuffer( parent );
303 pointNextBuffer->setData( createPointNextBuffer() );
304
305 Qt3DCore::QAttribute *pointNextAttribute = new Qt3DCore::QAttribute( parent );
306 pointNextAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
307 pointNextAttribute->setBuffer( pointNextBuffer );
308 pointNextAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
309 pointNextAttribute->setVertexSize( 3 );
310 pointNextAttribute->setByteStride( 3 * sizeof( float ) );
311 pointNextAttribute->setByteOffset( 0 );
312 pointNextAttribute->setCount( pointsNext.size() );
313 pointNextAttribute->setDivisor( 1 );
314 pointNextAttribute->setName( u"pointNext"_s );
315
316 Qt3DCore::QGeometry *geom = new Qt3DCore::QGeometry;
317 geom->addAttribute( positionAttribute );
318 geom->addAttribute( pointAAttribute );
319 geom->addAttribute( pointBAttribute );
320 geom->addAttribute( pointPrevAttribute );
321 geom->addAttribute( pointNextAttribute );
322
323 geom->setBoundingVolumePositionAttribute( pointAAttribute );
324
325 return geom;
326}
327
328Qt3DCore::QGeometry *QgsLineVertexData::createJoinGeometry( Qt3DCore::QNode *parent )
329{
330 static constexpr float selectorVertices[] = {
331 // triangle: p0, p1, p2
332 1.0f,
333 0.0f,
334 0.0f,
335 0.0f,
336 0.0f,
337 1.0f,
338 0.0f,
339 0.0f,
340 0.0f,
341 0.0f,
342 1.0f,
343 0.0f,
344 // triangle: p0, p2, p1Inner
345 1.0f,
346 0.0f,
347 0.0f,
348 0.0f,
349 0.0f,
350 0.0f,
351 1.0f,
352 0.0f,
353 0.0f,
354 0.0f,
355 0.0f,
356 1.0f,
357 };
358
359 Qt3DCore::QBuffer *selectorBuffer = new Qt3DCore::QBuffer( parent );
360 selectorBuffer->setData( QByteArray( reinterpret_cast<const char *>( selectorVertices ), sizeof( selectorVertices ) ) );
361
362 Qt3DCore::QAttribute *positionAttribute = new Qt3DCore::QAttribute( parent );
363 positionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
364 positionAttribute->setBuffer( selectorBuffer );
365 positionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
366 positionAttribute->setVertexSize( 4 );
367 positionAttribute->setByteStride( 4 * sizeof( float ) );
368 positionAttribute->setByteOffset( 0 );
369 positionAttribute->setCount( 6 );
370 positionAttribute->setName( Qt3DCore::QAttribute::defaultPositionAttributeName() );
371
372 Qt3DCore::QBuffer *pointABuffer = new Qt3DCore::QBuffer( parent );
373 pointABuffer->setData( createJoinPointABuffer() );
374
375 Qt3DCore::QAttribute *pointAAttribute = new Qt3DCore::QAttribute( parent );
376 pointAAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
377 pointAAttribute->setBuffer( pointABuffer );
378 pointAAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
379 pointAAttribute->setVertexSize( 3 );
380 pointAAttribute->setByteStride( 3 * sizeof( float ) );
381 pointAAttribute->setByteOffset( 0 );
382 pointAAttribute->setCount( joinPointA.size() );
383 pointAAttribute->setDivisor( 1 );
384 pointAAttribute->setName( u"pointA"_s );
385
386 Qt3DCore::QBuffer *pointBBuffer = new Qt3DCore::QBuffer( parent );
387 pointBBuffer->setData( createJoinPointBBuffer() );
388
389 Qt3DCore::QAttribute *pointBAttribute = new Qt3DCore::QAttribute( parent );
390 pointBAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
391 pointBAttribute->setBuffer( pointBBuffer );
392 pointBAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
393 pointBAttribute->setVertexSize( 3 );
394 pointBAttribute->setByteStride( 3 * sizeof( float ) );
395 pointBAttribute->setByteOffset( 0 );
396 pointBAttribute->setCount( joinPointB.size() );
397 pointBAttribute->setDivisor( 1 );
398 pointBAttribute->setName( u"pointB"_s );
399
400 Qt3DCore::QBuffer *pointCBuffer = new Qt3DCore::QBuffer( parent );
401 pointCBuffer->setData( createJoinPointCBuffer() );
402
403 Qt3DCore::QAttribute *pointCAttribute = new Qt3DCore::QAttribute( parent );
404 pointCAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
405 pointCAttribute->setBuffer( pointCBuffer );
406 pointCAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
407 pointCAttribute->setVertexSize( 3 );
408 pointCAttribute->setByteStride( 3 * sizeof( float ) );
409 pointCAttribute->setByteOffset( 0 );
410 pointCAttribute->setCount( joinPointC.size() );
411 pointCAttribute->setDivisor( 1 );
412 pointCAttribute->setName( u"pointC"_s );
413
414 Qt3DCore::QGeometry *geom = new Qt3DCore::QGeometry;
415 geom->addAttribute( positionAttribute );
416 geom->addAttribute( pointAAttribute );
417 geom->addAttribute( pointBAttribute );
418 geom->addAttribute( pointCAttribute );
419
420 geom->setBoundingVolumePositionAttribute( pointBAttribute );
421
422 return geom;
423}
424
425Qt3DCore::QEntity *QgsLineVertexData::createSegmentEntity( QgsMaterial *material, const QgsAbstractMaterialSettings *materialSettings, const QgsAbstractMaterial3DHandler *materialHandler )
426{
427 if ( pointsA.isEmpty() )
428 return nullptr;
429
430 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
431
432 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
433 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
434 Qt3DCore::QGeometry *geometry = createGeometry( entity );
435
436 if ( materialHandler && materialSettings && !materialDataDefined.isEmpty() )
437 materialHandler->applyDataDefinedToGeometry( materialSettings, geometry, pointsA.size(), materialDataDefined );
438
439 renderer->setGeometry( geometry );
440 renderer->setVertexCount( 6 );
441 renderer->setInstanceCount( pointsA.size() );
442
443 entity->addComponent( renderer );
444 if ( material )
445 entity->addComponent( material );
446
447 return entity;
448}
449
450Qt3DCore::QEntity *QgsLineVertexData::createJoinEntity( const QgsLineMaterial *segmentMaterial, const QgsAbstractMaterialSettings *materialSettings, const QgsAbstractMaterial3DHandler *materialHandler )
451{
452 if ( joinPointA.isEmpty() )
453 return nullptr;
454
455 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
456
457 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
458 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
459 Qt3DCore::QGeometry *geometry = createJoinGeometry( entity );
460
461 if ( materialHandler && materialSettings && !materialDataDefinedJoins.isEmpty() )
462 materialHandler->applyDataDefinedToGeometry( materialSettings, geometry, joinPointA.size(), materialDataDefinedJoins );
463
464 renderer->setGeometry( geometry );
465 renderer->setVertexCount( 6 );
466 renderer->setInstanceCount( joinPointA.size() );
467
468 QgsLineMaterial *joinMaterial = new QgsLineMaterial( QgsLineMaterial::LinePart::Join );
469 if ( segmentMaterial )
470 segmentMaterial->copyLineParametersTo( joinMaterial );
471
472 entity->addComponent( renderer );
473 entity->addComponent( joinMaterial );
474
475 return entity;
476}
477
AltitudeClamping
Altitude clamping.
Definition qgis.h:4245
AltitudeBinding
Altitude binding.
Definition qgis.h:4258
@ Centroid
Clamp just centroid of feature.
Definition qgis.h:4260
@ Vertex
Clamp every vertex of feature.
Definition qgis.h:4259
Rendering context for preparation of 3D entities.
static float clampAltitude(const QgsPoint &p, Qgis::AltitudeClamping altClamp, Qgis::AltitudeBinding altBind, float offset, const QgsPoint &centroid, const Qgs3DRenderContext &context)
Clamps altitude of a vertex according to the settings, returns Z value.
Abstract base class for material 3D handlers.
virtual void applyDataDefinedToGeometry(const QgsAbstractMaterialSettings *settings, Qt3DCore::QGeometry *geometry, int vertexCount, const QByteArray &dataDefinedBytes) const
Applies the data defined bytes, dataDefinedBytes, on the geometry by filling a specific vertex buffer...
Abstract base class for material settings.
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition qgscurve.cpp:180
Line string geometry type, with support for z-dimension and m-values.
QgsPoint centroid() const override
Returns the centroid of the geometry.
Base class for all materials used within QGIS 3D views.
Definition qgsmaterial.h:40
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double y
Definition qgspoint.h:57
QgsPoint pointN(int i) const
Returns the specified point from inside the simple curve.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33