Skip to content

Commit

Permalink
Make coordinates of vector data chunks independent from scene origin
Browse files Browse the repository at this point in the history
This is a continuation of work started in qgis#58948, handling all the cases
of data from vector layers.
  • Loading branch information
wonder-sk committed Oct 23, 2024
1 parent 8e6ffb1 commit 2c65c3a
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 99 deletions.
4 changes: 2 additions & 2 deletions src/3d/qgs3dutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ QMatrix4x4 Qgs3DUtils::stringToMatrix4x4( const QString &str )
return m;
}

void Qgs3DUtils::extractPointPositions( const QgsFeature &f, const Qgs3DRenderContext &context, Qgis::AltitudeClamping altClamp, QVector<QVector3D> &positions )
void Qgs3DUtils::extractPointPositions( const QgsFeature &f, const Qgs3DRenderContext &context, const QgsVector3D &chunkOrigin, Qgis::AltitudeClamping altClamp, QVector<QVector3D> &positions )
{
const QgsAbstractGeometry *g = f.geometry().constGet();
for ( auto it = g->vertices_begin(); it != g->vertices_end(); ++it )
Expand All @@ -513,7 +513,7 @@ void Qgs3DUtils::extractPointPositions( const QgsFeature &f, const Qgs3DRenderCo
h = terrainZ + geomZ;
break;
}
positions.append( QVector3D( pt.x() - context.origin().x(), h, -( pt.y() - context.origin().y() ) ) );
positions.append( QVector3D( pt.x() - chunkOrigin.x(), h, -( pt.y() - chunkOrigin.y() ) ) );
QgsDebugMsgLevel( QStringLiteral( "%1 %2 %3" ).arg( positions.last().x() ).arg( positions.last().y() ).arg( positions.last().z() ), 2 );
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgs3dutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class _3D_EXPORT Qgs3DUtils
static QMatrix4x4 stringToMatrix4x4( const QString &str );

//! Calculates (x,y,z) positions of (multi)point from the given feature
static void extractPointPositions( const QgsFeature &f, const Qgs3DRenderContext &context, Qgis::AltitudeClamping altClamp, QVector<QVector3D> &positions );
static void extractPointPositions( const QgsFeature &f, const Qgs3DRenderContext &context, const QgsVector3D &chunkOrigin, Qgis::AltitudeClamping altClamp, QVector<QVector3D> &positions );

/**
* Returns TRUE if bbox is completely outside the current viewing volume.
Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgsfeature3dhandler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class QgsFeature3DHandler
* Called before feature iteration starts to initialize, get required attributes.
* \returns TRUE on success (on FALSE the handler failed to initialize and processFeature() / finalize() should not be called
*/
virtual bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) = 0;
virtual bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin ) = 0;

/**
* Called for every feature to extract information out of it into some
Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgsrubberband3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ void QgsRubberBand3D::updateGeometry()
{
QgsLineVertexData lineData;
lineData.withAdjacency = true;
lineData.init( Qgis::AltitudeClamping::Absolute, Qgis::AltitudeBinding::Vertex, 0, Qgs3DRenderContext::fromMapSettings( mMapSettings ) );
lineData.init( Qgis::AltitudeClamping::Absolute, Qgis::AltitudeBinding::Vertex, 0, Qgs3DRenderContext::fromMapSettings( mMapSettings ), mMapSettings->origin() );
lineData.addLineString( mLineString );

mPositionAttribute->buffer()->setData( lineData.createVertexBuffer() );
Expand Down
6 changes: 3 additions & 3 deletions src/3d/qgsrulebased3drenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,12 @@ void QgsRuleBased3DRenderer::Rule::createHandlers( QgsVectorLayer *layer, QgsRul
}


void QgsRuleBased3DRenderer::Rule::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, QgsRuleBased3DRenderer::RuleToHandlerMap &handlers ) const
void QgsRuleBased3DRenderer::Rule::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin, QgsRuleBased3DRenderer::RuleToHandlerMap &handlers ) const
{
if ( mSymbol )
{
QgsFeature3DHandler *handler = handlers[this];
if ( !handler->prepare( context, attributeNames ) )
if ( !handler->prepare( context, attributeNames, chunkOrigin ) )
{
handlers.remove( this );
delete handler;
Expand All @@ -283,7 +283,7 @@ void QgsRuleBased3DRenderer::Rule::prepare( const Qgs3DRenderContext &context, Q
// call recursively
for ( Rule *rule : std::as_const( mChildren ) )
{
rule->prepare( context, attributeNames, handlers );
rule->prepare( context, attributeNames, chunkOrigin, handlers );
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgsrulebased3drenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class _3D_EXPORT QgsRuleBased3DRenderer : public QgsAbstractVectorLayer3DRendere
* call prepare() on handlers and populate attributeNames
* \note not available in Python bindings
*/
void prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, RuleToHandlerMap &handlers ) const SIP_SKIP;
void prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin, RuleToHandlerMap &handlers ) const SIP_SKIP;

/**
* register individual features
Expand Down
11 changes: 7 additions & 4 deletions src/3d/qgsrulebasedchunkloader_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ QgsRuleBasedChunkLoader::QgsRuleBasedChunkLoader( const QgsRuleBasedChunkLoaderF

QgsVectorLayer *layer = mFactory->mLayer;

// only a subset of data to be queried
const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), mContext.origin() );
// origin for coordinates of the chunk - it is kind of arbitrary, but it should be
// picked so that the coordinates are relatively small to avoid numerical precision issues
QgsVector3D chunkOrigin( rect.center().x(), rect.center().y(), 0 );

QgsExpressionContext exprContext( Qgs3DUtils::globalProjectLayerExpressionContext( layer ) );
exprContext.setFields( layer->fields() );
mContext.setExpressionContext( exprContext );
Expand All @@ -63,15 +69,12 @@ QgsRuleBasedChunkLoader::QgsRuleBasedChunkLoader( const QgsRuleBasedChunkLoaderF
mRootRule->createHandlers( layer, mHandlers );

QSet<QString> attributeNames;
mRootRule->prepare( mContext, attributeNames, mHandlers );
mRootRule->prepare( mContext, attributeNames, chunkOrigin, mHandlers );

// build the feature request
QgsFeatureRequest req;
req.setDestinationCrs( mContext.crs(), mContext.transformContext() );
req.setSubsetOfAttributes( attributeNames, layer->fields() );

// only a subset of data to be queried
const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), mContext.origin() );
req.setFilterRect( rect );

//
Expand Down
36 changes: 0 additions & 36 deletions src/3d/qgstessellatedpolygongeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,42 +82,6 @@ QgsTessellatedPolygonGeometry::QgsTessellatedPolygonGeometry( bool _withNormals,
}
}

void QgsTessellatedPolygonGeometry::setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon )
{
Q_ASSERT( polygons.count() == featureIds.count() );
mTriangleIndexStartingIndices.reserve( polygons.count() );
mTriangleIndexFids.reserve( polygons.count() );

QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals, mAddBackFaces, false, mAddTextureCoords );
for ( int i = 0; i < polygons.count(); ++i )
{
Q_ASSERT( tessellator.dataVerticesCount() % 3 == 0 );
const uint startingTriangleIndex = static_cast<uint>( tessellator.dataVerticesCount() / 3 );
mTriangleIndexStartingIndices.append( startingTriangleIndex );
mTriangleIndexFids.append( featureIds[i] );

QgsPolygon *polygon = polygons.at( i );
const float extr = extrusionHeightPerPolygon.isEmpty() ? extrusionHeight : extrusionHeightPerPolygon.at( i );
tessellator.addPolygon( *polygon, extr );
}
if ( !tessellator.error().isEmpty() )
{
QgsMessageLog::logMessage( tessellator.error(), QObject::tr( "3D" ) );
}

qDeleteAll( polygons );

const QByteArray data( ( const char * )tessellator.data().constData(), tessellator.data().count() * sizeof( float ) );
const int nVerts = data.count() / tessellator.stride();

mVertexBuffer->setData( data );
mPositionAttribute->setCount( nVerts );
if ( mNormalAttribute )
mNormalAttribute->setCount( nVerts );
if ( mAddTextureCoords )
mTextureCoordsAttribute->setCount( nVerts );
}

void QgsTessellatedPolygonGeometry::setData( const QByteArray &vertexBufferData, int vertexCount, const QVector<QgsFeatureId> &triangleIndexFids, const QVector<uint> &triangleIndexStartingIndices )
{
mTriangleIndexStartingIndices = triangleIndexStartingIndices;
Expand Down
3 changes: 0 additions & 3 deletions src/3d/qgstessellatedpolygongeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ class QgsTessellatedPolygonGeometry : public Qt3DCore::QGeometry
*/
void setAddTextureCoords( bool add ) { mAddTextureCoords = add; }

//! Initializes vertex buffer from given polygons. Takes ownership of passed polygon geometries
void setPolygons( const QList<QgsPolygon *> &polygons, const QList<QgsFeatureId> &featureIds, const QgsPointXY &origin, float extrusionHeight, const QList<float> &extrusionHeightPerPolygon = QList<float>() );

/**
* Initializes vertex buffer (and other members) from data that were already tessellated.
* This is an alternative to setPolygons() - this method does not do any expensive work in the body.
Expand Down
11 changes: 7 additions & 4 deletions src/3d/qgsvectorlayerchunkloader_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,18 @@ QgsVectorLayerChunkLoader::QgsVectorLayerChunkLoader( const QgsVectorLayerChunkL
}
mHandler.reset( handler );

// only a subset of data to be queried
const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), mRenderContext.origin() );
// origin for coordinates of the chunk - it is kind of arbitrary, but it should be
// picked so that the coordinates are relatively small to avoid numerical precision issues
QgsVector3D chunkOrigin( rect.center().x(), rect.center().y(), 0 );

QgsExpressionContext exprContext( Qgs3DUtils::globalProjectLayerExpressionContext( layer ) );
exprContext.setFields( layer->fields() );
mRenderContext.setExpressionContext( exprContext );

QSet<QString> attributeNames;
if ( !mHandler->prepare( mRenderContext, attributeNames ) )
if ( !mHandler->prepare( mRenderContext, attributeNames, chunkOrigin ) )
{
QgsDebugError( QStringLiteral( "Failed to prepare 3D feature handler!" ) );
return;
Expand All @@ -76,9 +82,6 @@ QgsVectorLayerChunkLoader::QgsVectorLayerChunkLoader( const QgsVectorLayerChunkL
QgsCoordinateTransform( layer->crs3D(), mRenderContext.crs(), mRenderContext.transformContext() )
);
req.setSubsetOfAttributes( attributeNames, layer->fields() );

// only a subset of data to be queried
const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), mRenderContext.origin() );
req.setFilterRect( rect );

//
Expand Down
39 changes: 31 additions & 8 deletions src/3d/symbols/qgsline3dsymbol_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "qgsphongtexturedmaterialsettings.h"
#include "qgsmessagelog.h"

#include <Qt3DCore/QTransform>
#include <Qt3DExtras/QPhongMaterial>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <Qt3DRender/QAttribute>
Expand Down Expand Up @@ -63,7 +64,7 @@ class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler
: mSymbol( static_cast< QgsLine3DSymbol *>( symbol->clone() ) )
, mSelectedIds( selectedIds ) {}

bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin ) override;
void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;

Expand All @@ -86,24 +87,29 @@ class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler
// inputs - generic
QgsFeatureIds mSelectedIds;

//! origin (in the map coordinates) for output geometries (e.g. at the center of the chunk)
QgsVector3D mChunkOrigin;

// outputs
LineData outNormal; //!< Features that are not selected
LineData outSelected; //!< Features that are selected
};



bool QgsBufferedLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
bool QgsBufferedLine3DSymbolHandler::prepare( const Qgs3DRenderContext &, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin )
{
Q_UNUSED( attributeNames )

mChunkOrigin = chunkOrigin;

const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol->materialSettings() );

outNormal.tessellator.reset( new QgsTessellator( context.origin().x(), context.origin().y(), true,
outNormal.tessellator.reset( new QgsTessellator( chunkOrigin.x(), chunkOrigin.y(), true,
false, false, false, texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false,
3,
texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) );
outSelected.tessellator.reset( new QgsTessellator( context.origin().x(), context.origin().y(), true,
outSelected.tessellator.reset( new QgsTessellator( chunkOrigin.x(), chunkOrigin.y(), true,
false, false, false, texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false,
3,
texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) );
Expand Down Expand Up @@ -217,10 +223,16 @@ void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, cons
Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
renderer->setGeometry( geometry );

// add transform (our geometry has coordinates relative to mChunkOrigin)
Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
QVector3D nodeTranslation = ( mChunkOrigin - context.origin() ).toVector3D();
tr->setTranslation( QVector3D( nodeTranslation.x(), nodeTranslation.z(), -nodeTranslation.y() ) );

// make entity
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
entity->addComponent( renderer );
entity->addComponent( mat );
entity->addComponent( tr );
entity->setParent( parent );

if ( !selected )
Expand All @@ -243,7 +255,7 @@ class QgsThickLine3DSymbolHandler : public QgsFeature3DHandler
{
}

bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin ) override;
void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;

Expand All @@ -259,21 +271,26 @@ class QgsThickLine3DSymbolHandler : public QgsFeature3DHandler
// inputs - generic
QgsFeatureIds mSelectedIds;

//! origin (in the map coordinates) for output geometries (e.g. at the center of the chunk)
QgsVector3D mChunkOrigin;

// outputs
QgsLineVertexData outNormal; //!< Features that are not selected
QgsLineVertexData outSelected; //!< Features that are selected
};



bool QgsThickLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
bool QgsThickLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin )
{
Q_UNUSED( attributeNames )

mChunkOrigin = chunkOrigin;

outNormal.withAdjacency = true;
outSelected.withAdjacency = true;
outNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context );
outSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context );
outNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, chunkOrigin );
outSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, chunkOrigin );

QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.expressionContext() );
attributeNames.unite( attrs );
Expand Down Expand Up @@ -374,9 +391,15 @@ void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Q
renderer->setPrimitiveRestartEnabled( true );
renderer->setRestartIndexValue( 0 );

// add transform (our geometry has coordinates relative to mChunkOrigin)
Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
QVector3D nodeTranslation = ( mChunkOrigin - context.origin() ).toVector3D();
tr->setTranslation( QVector3D( nodeTranslation.x(), nodeTranslation.z(), -nodeTranslation.y() ) );

// make entity
entity->addComponent( renderer );
entity->addComponent( mat );
entity->addComponent( tr );
entity->setParent( parent );
}

Expand Down
15 changes: 8 additions & 7 deletions src/3d/symbols/qgslinevertexdata_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ QgsLineVertexData::QgsLineVertexData()
vertices << QVector3D();
}

void QgsLineVertexData::init( Qgis::AltitudeClamping clamping, Qgis::AltitudeBinding binding, float height, const Qgs3DRenderContext &context )
void QgsLineVertexData::init( Qgis::AltitudeClamping clamping, Qgis::AltitudeBinding binding, float height, const Qgs3DRenderContext &context, const QgsVector3D &chunkOrigin )
{
altClamping = clamping;
altBinding = binding;
baseHeight = height;
renderContext = context;
origin = chunkOrigin;
}

QByteArray QgsLineVertexData::createVertexBuffer()
Expand Down Expand Up @@ -135,9 +136,9 @@ void QgsLineVertexData::addLineString( const QgsLineString &lineString, float ex
QgsPoint p = lineString.pointN( i );
float z = Qgs3DUtils::clampAltitude( p, altClamping, altBinding, baseHeight + extraHeightOffset, centroid, renderContext );

vertices << QVector3D( static_cast< float >( p.x() - renderContext.origin().x() ),
vertices << QVector3D( static_cast< float >( p.x() - origin.x() ),
z,
static_cast< float >( -( p.y() - renderContext.origin().y() ) ) );
static_cast< float >( -( p.y() - origin.y() ) ) );
indexes << vertices.count() - 1;
}

Expand Down Expand Up @@ -168,13 +169,13 @@ void QgsLineVertexData::addVerticalLines( const QgsLineString &lineString, float
if ( withAdjacency )
indexes << vertices.count(); // add the following vertex (for adjacency)

vertices << QVector3D( static_cast< float >( p.x() - renderContext.origin().x() ),
vertices << QVector3D( static_cast< float >( p.x() - origin.x() ),
z,
static_cast< float >( -( p.y() - renderContext.origin().y() ) ) );
static_cast< float >( -( p.y() - origin.y() ) ) );
indexes << vertices.count() - 1;
vertices << QVector3D( static_cast< float >( p.x() - renderContext.origin().x() ),
vertices << QVector3D( static_cast< float >( p.x() - origin.x() ),
z2,
static_cast< float >( -( p.y() - renderContext.origin().y() ) ) );
static_cast< float >( -( p.y() - origin.y() ) ) );
indexes << vertices.count() - 1;

if ( withAdjacency )
Expand Down
5 changes: 3 additions & 2 deletions src/3d/symbols/qgslinevertexdata_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ struct QgsLineVertexData
Qgis::AltitudeClamping altClamping = Qgis::AltitudeClamping::Relative;
Qgis::AltitudeBinding altBinding = Qgis::AltitudeBinding::Vertex;
float baseHeight = 0;
Qgs3DRenderContext renderContext;
Qgs3DRenderContext renderContext; // used for altitude clamping
QgsVector3D origin; // all coordinates are relative to this origin (e.g. center of the chunk)

QgsLineVertexData();

void init( Qgis::AltitudeClamping clamping, Qgis::AltitudeBinding binding, float height, const Qgs3DRenderContext &renderContext );
void init( Qgis::AltitudeClamping clamping, Qgis::AltitudeBinding binding, float height, const Qgs3DRenderContext &renderContext, const QgsVector3D &chunkOrigin );

QByteArray createVertexBuffer();
QByteArray createIndexBuffer();
Expand Down
Loading

0 comments on commit 2c65c3a

Please sign in to comment.