43#include <Qt3DCore/QAttribute>
44#include <Qt3DCore/QBuffer>
45#include <Qt3DCore/QEntity>
46#include <Qt3DCore/QGeometry>
47#include <Qt3DRender/QGeometryRenderer>
49using namespace Qt::StringLiterals;
55 : mMapSettings( &map )
57 , mGeometryType( geometryType )
59 Qt3DCore::QEntity *parentEntity = mEngine->frameGraph()->rubberBandRenderView().rubberBandEntity();
61 switch ( mGeometryType )
64 setupMarker( parentEntity );
67 setupLine( parentEntity );
68 setupMarker( parentEntity );
71 setupMarker( parentEntity );
72 setupLine( parentEntity );
73 setupPolygon( parentEntity );
77 QgsDebugError(
"Unknown GeometryType used in QgsRubberband3D" );
82void QgsRubberBand3D::setupMarker( Qt3DCore::QEntity *parentEntity )
86 mMarkerGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
87 mMarkerGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::TriangleStrip );
88 mMarkerGeometryRenderer->setGeometry( mMarkerGeometry );
89 mMarkerGeometryRenderer->setVertexCount( 4 );
91 setMarkerType( mMarkerType );
92 mMarkerEntity->addComponent( mMarkerGeometryRenderer );
94 mMarkerTransform =
new QgsGeoTransform;
95 mMarkerTransform->setOrigin( mMapSettings->origin() );
96 mMarkerEntity->addComponent( mMarkerTransform );
99void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity )
103 QgsLineVertexData dummyLineData;
104 mLineGeometry = dummyLineData.createGeometry( mLineEntity );
106 Q_ASSERT( mLineGeometry->attributes().count() == 2 );
107 mPositionAttribute = mLineGeometry->attributes().at( 0 );
108 mIndexAttribute = mLineGeometry->attributes().at( 1 );
110 mLineGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
111 mLineGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
112 mLineGeometryRenderer->setGeometry( mLineGeometry );
113 mLineGeometryRenderer->setPrimitiveRestartEnabled(
true );
114 mLineGeometryRenderer->setRestartIndexValue( 0 );
116 mLineEntity->addComponent( mLineGeometryRenderer );
118 mLineMaterial =
new QgsLineMaterial;
119 mLineMaterial->setLineWidth( mWidth );
120 mLineMaterial->setLineColor( mColor );
123 mLineMaterial->setViewportSize( mEngine->size() );
125 mLineEntity->addComponent( mLineMaterial );
127 mLineTransform =
new QgsGeoTransform;
128 mLineTransform->setOrigin( mMapSettings->origin() );
129 mLineEntity->addComponent( mLineTransform );
132void QgsRubberBand3D::setupPolygon( Qt3DCore::QEntity *parentEntity )
138 Qt3DRender::QGeometryRenderer *polygonGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
139 polygonGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
140 polygonGeometryRenderer->setGeometry( mPolygonGeometry );
141 mPolygonEntity->addComponent( polygonGeometryRenderer );
143 QColor color = mColor;
144 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
145 mPolygonMaterial =
new QgsUnlitMaterial();
146 mPolygonMaterial->setColor( color );
148 mPolygonEntity->addComponent( mPolygonMaterial );
150 mPolygonTransform =
new QgsGeoTransform;
151 mPolygonTransform->setOrigin( mMapSettings->origin() );
152 mPolygonEntity->addComponent( mPolygonTransform );
155void QgsRubberBand3D::removePoint(
int index )
160 const int vertexIndex = index < 0 ? lineString->
numPoints() - 1 + index : index;
170 const int vertexIndex = index < 0 ? lineString->
numPoints() + index : index;
181QgsRubberBand3D::~QgsRubberBand3D()
183 if ( mPolygonEntity )
185 mPolygonEntity.reset();
193 mMarkerEntity.reset();
198float QgsRubberBand3D::width()
const
203void QgsRubberBand3D::setWidth(
float width )
208 if ( isLineOrPolygon && mEdgesEnabled )
211 mLineMaterial->setLineWidth( width );
215 mMarkerSymbol->setSize( width );
216 updateMarkerMaterial();
219QColor QgsRubberBand3D::color()
const
224void QgsRubberBand3D::setColor(
const QColor color )
229 if ( mEdgesEnabled && isLineOrPolygon )
231 mLineMaterial->setLineColor( color );
234 if ( isLineOrPolygon )
236 mMarkerSymbol->setColor( color.lighter( 130 ) );
240 mMarkerSymbol->setColor( color );
243 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 && !mOutlineColor.value() )
245 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
247 updateMarkerMaterial();
251 if ( mPolygonMaterial )
252 mPolygonEntity->removeComponent( mPolygonMaterial );
254 if ( mPolygonFillEnabled )
256 QColor color = mColor;
257 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
258 mPolygonMaterial =
new QgsUnlitMaterial();
259 mPolygonMaterial->setColor( color );
260 mPolygonEntity->addComponent( mPolygonMaterial );
265QColor QgsRubberBand3D::outlineColor()
const
267 return mOutlineColor;
270void QgsRubberBand3D::setOutlineColor(
const QColor color )
272 mOutlineColor = color;
274 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 )
276 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
278 updateMarkerMaterial();
281void QgsRubberBand3D::setMarkerType(
const MarkerType marker )
283 mMarkerType = marker;
287 const QVariantMap props {
288 { u
"color"_s, lineOrPolygon ? mColor.lighter( 130 ).name() : mColor.name() },
289 { u
"size_unit"_s, u
"pixel"_s },
290 { u
"size"_s, QString::number( lineOrPolygon ? mWidth * 3.f : mWidth ) },
291 { u
"outline_color"_s, mOutlineColor.value() ? mOutlineColor.name() : mColor.name() },
293 { u
"outline_width"_s, QString::number( lineOrPolygon ? 0.5 : 1 ) },
294 { u
"name"_s, mMarkerType == Square ? u
"square"_s : u
"circle"_s }
298 updateMarkerMaterial();
301QgsRubberBand3D::MarkerType QgsRubberBand3D::markerType()
const
306void QgsRubberBand3D::setMarkerOutlineStyle(
const Qt::PenStyle style )
308 mMarkerOutlineStyle = style;
309 setMarkerType( markerType() );
312Qt::PenStyle QgsRubberBand3D::markerOutlineStyle()
const
314 return mMarkerOutlineStyle;
317void QgsRubberBand3D::setMarkersEnabled(
const bool enable )
319 mMarkerEnabled = enable;
320 updateMarkerMaterial();
323bool QgsRubberBand3D::hasMarkersEnabled()
const
325 return mMarkerEnabled;
328void QgsRubberBand3D::setEdgesEnabled(
const bool enable )
330 mEdgesEnabled = enable;
334bool QgsRubberBand3D::hasEdgesEnabled()
const
336 return mEdgesEnabled;
339void QgsRubberBand3D::setFillEnabled(
const bool enable )
341 mPolygonFillEnabled = enable;
345bool QgsRubberBand3D::hasFillEnabled()
const
347 return mPolygonFillEnabled;
350void QgsRubberBand3D::reset()
352 mGeometry.set(
nullptr );
356void QgsRubberBand3D::addPoint(
const QgsPoint &pt )
361 const int lastVertexIndex = exteriorRing->
numPoints() - 1;
373 else if ( !mGeometry.constGet() )
375 mGeometry.set(
new QgsLineString( QVector<QgsPoint> { pt } ) );
381void QgsRubberBand3D::setGeometry(
const QgsGeometry &geometry )
383 mGeometry = geometry;
384 mGeometryType = geometry.
type();
389void QgsRubberBand3D::removeLastPoint()
394void QgsRubberBand3D::removePenultimatePoint()
399void QgsRubberBand3D::moveLastPoint(
const QgsPoint &pt )
404 const int lastVertexIndex = lineString->
numPoints() - 2;
409 const int lastVertexIndex = lineString->
numPoints() - 1;
420void QgsRubberBand3D::updateGeometry()
423 const QgsBox3D box = mGeometry.constGet() ? mGeometry.constGet()->boundingBox3D() :
QgsBox3D();
426 QgsLineVertexData lineData;
427 lineData.withAdjacency =
true;
433 const int lastVertexIndex = lineString->
numPoints() - 1;
435 lineData.addLineString( *lineString, 0,
true );
439 lineData.addLineString( *lineString, 0,
false );
445 mPositionAttribute->buffer()->setData( lineData.createVertexBuffer() );
446 mIndexAttribute->buffer()->setData( lineData.createIndexBuffer() );
447 mLineGeometryRenderer->setVertexCount(
static_cast<int>( lineData.indexes.count() ) );
448 mLineTransform->setGeoTranslation( dataOrigin );
452 lineData.vertices.pop_front();
455 if ( mHideLastMarker && !lineData.vertices.isEmpty() )
456 lineData.vertices.pop_back();
458 mMarkerGeometry->setPositions( lineData.vertices );
459 mMarkerGeometryRenderer->setVertexCount( 4 );
460 mMarkerGeometryRenderer->setInstanceCount( lineData.vertices.count() );
461 mMarkerTransform->setGeoTranslation( dataOrigin );
468 tessellator.
setOrigin( mMapSettings->origin() );
471 if ( !tessellator.
error().isEmpty() )
476 const QByteArray vertexBuffer = tessellator.
vertexBuffer();
477 const QByteArray indexBuffer = tessellator.
indexBuffer();
481 mPolygonGeometry->setVertexBufferData( vertexBuffer, vertexCount, QVector<QgsFeatureId>(), QVector<uint>() );
482 mPolygonGeometry->setIndexBufferData( indexBuffer, indexCount );
483 mPolygonTransform->setGeoTranslation( mMapSettings->origin() );
487 mPolygonGeometry->setVertexBufferData( QByteArray(), 0, QVector<QgsFeatureId>(), QVector<uint>() );
488 mPolygonGeometry->setIndexBufferData( QByteArray(), 0 );
493void QgsRubberBand3D::updateMarkerMaterial()
495 if ( mMarkerEnabled )
497 if ( !mMarkerMaterial )
500 mMarkerEntity->addComponent( mMarkerMaterial );
502 QObject::connect( mEngine, &
QgsAbstract3DEngine::sizeChanged, mMarkerMaterial, [material = mMarkerMaterial, engine = mEngine] { material->setViewportSize( engine->
size() ); } );
506 mMarkerMaterial->setViewportSize( mEngine->size() );
508 else if ( !mMarkerEnabled && mMarkerMaterial )
510 mMarkerEntity->removeComponent( mMarkerMaterial );
511 mMarkerMaterial->setParent(
static_cast<Qt3DCore::QEntity *
>(
nullptr ) );
512 mMarkerMaterial->deleteLater();
513 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.
static Qgs3DRenderContext fromMapSettings(const Qgs3DMapSettings *mapSettings)
Creates an initialized Qgs3DRenderContext instance from given Qgs3DMapSettings.
Base class for 3D engine implementation.
void sizeChanged()
Emitted after a call to setSize().
virtual QSize size() const =0
Returns size of the engine's rendering area in pixels.
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.