44#include <Qt3DCore/QAttribute>
45#include <Qt3DCore/QBuffer>
46#include <Qt3DCore/QEntity>
47#include <Qt3DCore/QGeometry>
48#include <Qt3DRender/QGeometryRenderer>
50using namespace Qt::StringLiterals;
56 : mMapSettings( scene->mapSettings() )
57 , mEngine( scene->engine() )
58 , mGeometryType( geometryType )
60 Qt3DCore::QEntity *parentEntity = mEngine->frameGraph()->rubberBandRenderView().rubberBandEntity();
62 switch ( mGeometryType )
65 setupMarker( parentEntity );
68 setupLine( parentEntity );
69 setupMarker( parentEntity );
72 setupMarker( parentEntity );
73 setupLine( parentEntity );
74 setupPolygon( parentEntity );
78 QgsDebugError(
"Unknown GeometryType used in QgsRubberband3D" );
83void QgsRubberBand3D::setupMarker( Qt3DCore::QEntity *parentEntity )
87 mMarkerGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
88 mMarkerGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::TriangleStrip );
89 mMarkerGeometryRenderer->setGeometry( mMarkerGeometry );
90 mMarkerGeometryRenderer->setVertexCount( 4 );
91 mMarkerGeometryRenderer->setInstanceCount( 0 );
93 setMarkerType( mMarkerType );
94 mMarkerEntity->addComponent( mMarkerGeometryRenderer );
96 mMarkerTransform =
new QgsGeoTransform;
97 mMarkerTransform->setOrigin( mMapSettings->origin() );
98 mMarkerEntity->addComponent( mMarkerTransform );
101void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity )
105 QgsLineVertexData dummyLineData;
106 mLineGeometry = dummyLineData.createGeometry( mLineEntity );
108 Q_ASSERT( mLineGeometry->attributes().count() == 2 );
109 mPositionAttribute = mLineGeometry->attributes().at( 0 );
110 mIndexAttribute = mLineGeometry->attributes().at( 1 );
112 mLineGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
113 mLineGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
114 mLineGeometryRenderer->setGeometry( mLineGeometry );
115 mLineGeometryRenderer->setPrimitiveRestartEnabled(
true );
116 mLineGeometryRenderer->setRestartIndexValue( 0 );
118 mLineEntity->addComponent( mLineGeometryRenderer );
120 mLineMaterial =
new QgsLineMaterial;
121 mLineMaterial->setLineWidth( mWidth );
122 mLineMaterial->setLineColor( mColor );
125 mLineMaterial->setViewportSize( mEngine->size() );
127 mLineEntity->addComponent( mLineMaterial );
129 mLineTransform =
new QgsGeoTransform;
130 mLineTransform->setOrigin( mMapSettings->origin() );
131 mLineEntity->addComponent( mLineTransform );
134void QgsRubberBand3D::setupPolygon( Qt3DCore::QEntity *parentEntity )
140 Qt3DRender::QGeometryRenderer *polygonGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
141 polygonGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
142 polygonGeometryRenderer->setGeometry( mPolygonGeometry );
143 mPolygonEntity->addComponent( polygonGeometryRenderer );
145 QColor color = mColor;
146 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
147 mPolygonMaterial =
new QgsUnlitMaterial();
148 mPolygonMaterial->setColor( color );
150 mPolygonEntity->addComponent( mPolygonMaterial );
152 mPolygonTransform =
new QgsGeoTransform;
153 mPolygonTransform->setOrigin( mMapSettings->origin() );
154 mPolygonEntity->addComponent( mPolygonTransform );
157void QgsRubberBand3D::removePoint(
int index )
162 const int vertexIndex = index < 0 ? lineString->
numPoints() - 1 + index : index;
172 const int vertexIndex = index < 0 ? lineString->
numPoints() + index : index;
183QgsRubberBand3D::~QgsRubberBand3D()
185 if ( mPolygonEntity )
187 mPolygonEntity.reset();
195 mMarkerEntity.reset();
200float QgsRubberBand3D::width()
const
205void QgsRubberBand3D::setWidth(
float width )
210 if ( isLineOrPolygon && mEdgesEnabled )
213 mLineMaterial->setLineWidth( width );
217 mMarkerSymbol->setSize( width );
218 updateMarkerMaterial();
221QColor QgsRubberBand3D::color()
const
226void QgsRubberBand3D::setColor(
const QColor color )
231 if ( mEdgesEnabled && isLineOrPolygon )
233 mLineMaterial->setLineColor( color );
236 if ( isLineOrPolygon )
238 mMarkerSymbol->setColor( color.lighter( 130 ) );
242 mMarkerSymbol->setColor( color );
245 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 && !mOutlineColor.value() )
247 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
249 updateMarkerMaterial();
253 if ( mPolygonMaterial )
254 mPolygonEntity->removeComponent( mPolygonMaterial );
256 if ( mPolygonFillEnabled )
258 QColor color = mColor;
259 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
260 mPolygonMaterial =
new QgsUnlitMaterial();
261 mPolygonMaterial->setColor( color );
262 mPolygonEntity->addComponent( mPolygonMaterial );
267QColor QgsRubberBand3D::outlineColor()
const
269 return mOutlineColor;
272void QgsRubberBand3D::setOutlineColor(
const QColor color )
274 mOutlineColor = color;
276 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 )
278 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
280 updateMarkerMaterial();
283void QgsRubberBand3D::setMarkerType(
const MarkerType marker )
285 mMarkerType = marker;
289 const QVariantMap props {
290 { u
"color"_s, lineOrPolygon ? mColor.lighter( 130 ).name() : mColor.name() },
291 { u
"size_unit"_s, u
"pixel"_s },
292 { u
"size"_s, QString::number( lineOrPolygon ? mWidth * 3.f : mWidth ) },
293 { u
"outline_color"_s, mOutlineColor.value() ? mOutlineColor.name() : mColor.name() },
295 { u
"outline_width"_s, QString::number( lineOrPolygon ? 0.5 : 1 ) },
296 { u
"name"_s, mMarkerType == Square ? u
"square"_s : u
"circle"_s }
300 updateMarkerMaterial();
303QgsRubberBand3D::MarkerType QgsRubberBand3D::markerType()
const
308void QgsRubberBand3D::setMarkerOutlineStyle(
const Qt::PenStyle style )
310 mMarkerOutlineStyle = style;
311 setMarkerType( markerType() );
314Qt::PenStyle QgsRubberBand3D::markerOutlineStyle()
const
316 return mMarkerOutlineStyle;
319void QgsRubberBand3D::setMarkersEnabled(
const bool enable )
321 mMarkerEnabled = enable;
322 updateMarkerMaterial();
325bool QgsRubberBand3D::hasMarkersEnabled()
const
327 return mMarkerEnabled;
330void QgsRubberBand3D::setEdgesEnabled(
const bool enable )
332 mEdgesEnabled = enable;
336bool QgsRubberBand3D::hasEdgesEnabled()
const
338 return mEdgesEnabled;
341void QgsRubberBand3D::setFillEnabled(
const bool enable )
343 mPolygonFillEnabled = enable;
347bool QgsRubberBand3D::hasFillEnabled()
const
349 return mPolygonFillEnabled;
352void QgsRubberBand3D::reset()
354 mGeometry.set(
nullptr );
358void QgsRubberBand3D::addPoint(
const QgsPoint &pt )
363 const int lastVertexIndex = exteriorRing->
numPoints() - 1;
375 else if ( !mGeometry.constGet() )
377 mGeometry.set(
new QgsLineString( QVector<QgsPoint> { pt } ) );
383void QgsRubberBand3D::setGeometry(
const QgsGeometry &geometry )
385 mGeometry = geometry;
386 mGeometryType = geometry.
type();
391void QgsRubberBand3D::removeLastPoint()
396void QgsRubberBand3D::removePenultimatePoint()
401void QgsRubberBand3D::moveLastPoint(
const QgsPoint &pt )
406 const int lastVertexIndex = lineString->
numPoints() - 2;
411 const int lastVertexIndex = lineString->
numPoints() - 1;
422void QgsRubberBand3D::updateGeometry()
425 const QgsBox3D box = mGeometry.constGet() ? mGeometry.constGet()->boundingBox3D() :
QgsBox3D();
428 QgsLineVertexData lineData;
429 lineData.withAdjacency =
true;
435 const int lastVertexIndex = lineString->
numPoints() - 1;
437 lineData.addLineString( *lineString, 0,
true );
441 lineData.addLineString( *lineString, 0,
false );
447 mPositionAttribute->buffer()->setData( lineData.createVertexBuffer() );
448 mIndexAttribute->buffer()->setData( lineData.createIndexBuffer() );
449 mLineGeometryRenderer->setVertexCount(
static_cast<int>( lineData.indexes.count() ) );
450 mLineTransform->setGeoTranslation( dataOrigin );
454 lineData.vertices.pop_front();
457 if ( mHideLastMarker && !lineData.vertices.isEmpty() )
458 lineData.vertices.pop_back();
460 mMarkerGeometry->setPositions( lineData.vertices );
461 mMarkerGeometryRenderer->setVertexCount( 4 );
462 mMarkerGeometryRenderer->setInstanceCount( lineData.vertices.count() );
463 mMarkerTransform->setGeoTranslation( dataOrigin );
470 tessellator.
setOrigin( mMapSettings->origin() );
473 if ( !tessellator.
error().isEmpty() )
478 const QByteArray vertexBuffer = tessellator.
vertexBuffer();
479 const QByteArray indexBuffer = tessellator.
indexBuffer();
483 mPolygonGeometry->setVertexBufferData( vertexBuffer, vertexCount, QVector<QgsFeatureId>(), QVector<uint>() );
484 mPolygonGeometry->setIndexBufferData( indexBuffer, indexCount );
485 mPolygonTransform->setGeoTranslation( mMapSettings->origin() );
489 mPolygonGeometry->setVertexBufferData( QByteArray(), 0, QVector<QgsFeatureId>(), QVector<uint>() );
490 mPolygonGeometry->setIndexBufferData( QByteArray(), 0 );
495void QgsRubberBand3D::updateMarkerMaterial()
497 if ( mMarkerEnabled )
499 if ( !mMarkerMaterial )
502 mMarkerEntity->addComponent( mMarkerMaterial );
504 QObject::connect( mEngine, &
QgsAbstract3DEngine::sizeChanged, mMarkerMaterial, [material = mMarkerMaterial, engine = mEngine] { material->setViewportSize( engine->size() ); } );
508 mMarkerMaterial->setViewportSize( mEngine->size() );
510 else if ( !mMarkerEnabled && mMarkerMaterial )
512 mMarkerEntity->removeComponent( mMarkerMaterial );
513 mMarkerMaterial->setParent(
static_cast<Qt3DCore::QEntity *
>(
nullptr ) );
514 mMarkerMaterial->deleteLater();
515 mMarkerMaterial =
nullptr;
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ Vertex
Clamp every vertex of feature.
@ Globe
Scene is represented as a globe using a geocentric CRS.
Entity that encapsulates our 3D scene - contains all other entities (such as terrain) as children.
static Qgs3DRenderContext fromMapSettings(const Qgs3DMapSettings *mapSettings)
Creates an initialized Qgs3DRenderContext instance from given Qgs3DMapSettings.
void sizeChanged()
Emitted after a call to setSize().
Geometry of the billboard rendering for points in 3D map view.
A 3-dimensional box composed of x, y, z coordinates.
QgsVector3D center() const
Returns the center of the box as a vector.
bool isNull() const
Test if the box is null (holding no spatial information).
A geometry is the spatial representation of a feature.
Line string geometry type, with support for z-dimension and m-values.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
static std::unique_ptr< QgsMarkerSymbol > createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Material of the billboard rendering for points in 3D map view.
Point geometry type, with support for z-dimension and m-values.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
int numPoints() const override
Returns the number of points in the curve.
static QString encodePenStyle(Qt::PenStyle style)
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
Tessellates polygons into triangles.
void setOrigin(const QgsVector3D &origin)
Sets the origin point of the map.
QByteArray vertexBuffer() const
Returns vertex buffer for the generated points.
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array.
int uniqueVertexCount() const
Returns unique vertex count.
QByteArray indexBuffer() const
Returns index buffer for the generated points.
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.
void setAddNormals(bool addNormals)
Sets whether normals should be added to the output data.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
T qgsgeometry_cast(QgsAbstractGeometry *geom)
#define QgsDebugError(str)
constexpr QObjectUniquePtr< Tp > make_qobject_unique(Args &&...args)
Create an object owned by a QObjectUniquePtr.
Utility class for identifying a unique vertex within a geometry.