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 );
92 setMarkerType( mMarkerType );
93 mMarkerEntity->addComponent( mMarkerGeometryRenderer );
95 mMarkerTransform =
new QgsGeoTransform;
96 mMarkerTransform->setOrigin( mMapSettings->origin() );
97 mMarkerEntity->addComponent( mMarkerTransform );
100void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity )
104 QgsLineVertexData dummyLineData;
105 mLineGeometry = dummyLineData.createGeometry( mLineEntity );
107 Q_ASSERT( mLineGeometry->attributes().count() == 2 );
108 mPositionAttribute = mLineGeometry->attributes().at( 0 );
109 mIndexAttribute = mLineGeometry->attributes().at( 1 );
111 mLineGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
112 mLineGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
113 mLineGeometryRenderer->setGeometry( mLineGeometry );
114 mLineGeometryRenderer->setPrimitiveRestartEnabled(
true );
115 mLineGeometryRenderer->setRestartIndexValue( 0 );
117 mLineEntity->addComponent( mLineGeometryRenderer );
119 mLineMaterial =
new QgsLineMaterial;
120 mLineMaterial->setLineWidth( mWidth );
121 mLineMaterial->setLineColor( mColor );
124 mLineMaterial->setViewportSize( mEngine->size() );
126 mLineEntity->addComponent( mLineMaterial );
128 mLineTransform =
new QgsGeoTransform;
129 mLineTransform->setOrigin( mMapSettings->origin() );
130 mLineEntity->addComponent( mLineTransform );
133void QgsRubberBand3D::setupPolygon( Qt3DCore::QEntity *parentEntity )
139 Qt3DRender::QGeometryRenderer *polygonGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
140 polygonGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
141 polygonGeometryRenderer->setGeometry( mPolygonGeometry );
142 mPolygonEntity->addComponent( polygonGeometryRenderer );
144 QColor color = mColor;
145 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
146 mPolygonMaterial =
new QgsUnlitMaterial();
147 mPolygonMaterial->setColor( color );
149 mPolygonEntity->addComponent( mPolygonMaterial );
151 mPolygonTransform =
new QgsGeoTransform;
152 mPolygonTransform->setOrigin( mMapSettings->origin() );
153 mPolygonEntity->addComponent( mPolygonTransform );
156void QgsRubberBand3D::removePoint(
int index )
161 const int vertexIndex = index < 0 ? lineString->
numPoints() - 1 + index : index;
171 const int vertexIndex = index < 0 ? lineString->
numPoints() + index : index;
182QgsRubberBand3D::~QgsRubberBand3D()
184 if ( mPolygonEntity )
186 mPolygonEntity.reset();
194 mMarkerEntity.reset();
199float QgsRubberBand3D::width()
const
204void QgsRubberBand3D::setWidth(
float width )
209 if ( isLineOrPolygon && mEdgesEnabled )
212 mLineMaterial->setLineWidth( width );
216 mMarkerSymbol->setSize( width );
217 updateMarkerMaterial();
220QColor QgsRubberBand3D::color()
const
225void QgsRubberBand3D::setColor(
const QColor color )
230 if ( mEdgesEnabled && isLineOrPolygon )
232 mLineMaterial->setLineColor( color );
235 if ( isLineOrPolygon )
237 mMarkerSymbol->setColor( color.lighter( 130 ) );
241 mMarkerSymbol->setColor( color );
244 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 && !mOutlineColor.value() )
246 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
248 updateMarkerMaterial();
252 if ( mPolygonMaterial )
253 mPolygonEntity->removeComponent( mPolygonMaterial );
255 if ( mPolygonFillEnabled )
257 QColor color = mColor;
258 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
259 mPolygonMaterial =
new QgsUnlitMaterial();
260 mPolygonMaterial->setColor( color );
261 mPolygonEntity->addComponent( mPolygonMaterial );
266QColor QgsRubberBand3D::outlineColor()
const
268 return mOutlineColor;
271void QgsRubberBand3D::setOutlineColor(
const QColor color )
273 mOutlineColor = color;
275 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 )
277 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
279 updateMarkerMaterial();
282void QgsRubberBand3D::setMarkerType(
const MarkerType marker )
284 mMarkerType = marker;
288 const QVariantMap props {
289 { u
"color"_s, lineOrPolygon ? mColor.lighter( 130 ).name() : mColor.name() },
290 { u
"size_unit"_s, u
"pixel"_s },
291 { u
"size"_s, QString::number( lineOrPolygon ? mWidth * 3.f : mWidth ) },
292 { u
"outline_color"_s, mOutlineColor.value() ? mOutlineColor.name() : mColor.name() },
294 { u
"outline_width"_s, QString::number( lineOrPolygon ? 0.5 : 1 ) },
295 { u
"name"_s, mMarkerType == Square ? u
"square"_s : u
"circle"_s }
299 updateMarkerMaterial();
302QgsRubberBand3D::MarkerType QgsRubberBand3D::markerType()
const
307void QgsRubberBand3D::setMarkerOutlineStyle(
const Qt::PenStyle style )
309 mMarkerOutlineStyle = style;
310 setMarkerType( markerType() );
313Qt::PenStyle QgsRubberBand3D::markerOutlineStyle()
const
315 return mMarkerOutlineStyle;
318void QgsRubberBand3D::setMarkersEnabled(
const bool enable )
320 mMarkerEnabled = enable;
321 updateMarkerMaterial();
324bool QgsRubberBand3D::hasMarkersEnabled()
const
326 return mMarkerEnabled;
329void QgsRubberBand3D::setEdgesEnabled(
const bool enable )
331 mEdgesEnabled = enable;
335bool QgsRubberBand3D::hasEdgesEnabled()
const
337 return mEdgesEnabled;
340void QgsRubberBand3D::setFillEnabled(
const bool enable )
342 mPolygonFillEnabled = enable;
346bool QgsRubberBand3D::hasFillEnabled()
const
348 return mPolygonFillEnabled;
351void QgsRubberBand3D::reset()
353 mGeometry.set(
nullptr );
357void QgsRubberBand3D::addPoint(
const QgsPoint &pt )
362 const int lastVertexIndex = exteriorRing->
numPoints() - 1;
374 else if ( !mGeometry.constGet() )
376 mGeometry.set(
new QgsLineString( QVector<QgsPoint> { pt } ) );
382void QgsRubberBand3D::setGeometry(
const QgsGeometry &geometry )
384 mGeometry = geometry;
385 mGeometryType = geometry.
type();
390void QgsRubberBand3D::removeLastPoint()
395void QgsRubberBand3D::removePenultimatePoint()
400void QgsRubberBand3D::moveLastPoint(
const QgsPoint &pt )
405 const int lastVertexIndex = lineString->
numPoints() - 2;
410 const int lastVertexIndex = lineString->
numPoints() - 1;
421void QgsRubberBand3D::updateGeometry()
424 const QgsBox3D box = mGeometry.constGet() ? mGeometry.constGet()->boundingBox3D() :
QgsBox3D();
427 QgsLineVertexData lineData;
428 lineData.withAdjacency =
true;
434 const int lastVertexIndex = lineString->
numPoints() - 1;
436 lineData.addLineString( *lineString, 0,
true );
440 lineData.addLineString( *lineString, 0,
false );
446 mPositionAttribute->buffer()->setData( lineData.createVertexBuffer() );
447 mIndexAttribute->buffer()->setData( lineData.createIndexBuffer() );
448 mLineGeometryRenderer->setVertexCount(
static_cast<int>( lineData.indexes.count() ) );
449 mLineTransform->setGeoTranslation( dataOrigin );
453 lineData.vertices.pop_front();
456 if ( mHideLastMarker && !lineData.vertices.isEmpty() )
457 lineData.vertices.pop_back();
459 mMarkerGeometry->setPositions( lineData.vertices );
460 mMarkerGeometryRenderer->setVertexCount( 4 );
461 mMarkerGeometryRenderer->setInstanceCount( lineData.vertices.count() );
462 mMarkerTransform->setGeoTranslation( dataOrigin );
469 tessellator.
setOrigin( mMapSettings->origin() );
472 if ( !tessellator.
error().isEmpty() )
477 const QByteArray vertexBuffer = tessellator.
vertexBuffer();
478 const QByteArray indexBuffer = tessellator.
indexBuffer();
482 mPolygonGeometry->setVertexBufferData( vertexBuffer, vertexCount, QVector<QgsFeatureId>(), QVector<uint>() );
483 mPolygonGeometry->setIndexBufferData( indexBuffer, indexCount );
484 mPolygonTransform->setGeoTranslation( mMapSettings->origin() );
488 mPolygonGeometry->setVertexBufferData( QByteArray(), 0, QVector<QgsFeatureId>(), QVector<uint>() );
489 mPolygonGeometry->setIndexBufferData( QByteArray(), 0 );
494void QgsRubberBand3D::updateMarkerMaterial()
496 if ( mMarkerEnabled )
498 if ( !mMarkerMaterial )
501 mMarkerEntity->addComponent( mMarkerMaterial );
503 QObject::connect( mEngine, &
QgsAbstract3DEngine::sizeChanged, mMarkerMaterial, [material = mMarkerMaterial, engine = mEngine] { material->setViewportSize( engine->size() ); } );
507 mMarkerMaterial->setViewportSize( mEngine->size() );
509 else if ( !mMarkerEnabled && mMarkerMaterial )
511 mMarkerEntity->removeComponent( mMarkerMaterial );
512 mMarkerMaterial->setParent(
static_cast<Qt3DCore::QEntity *
>(
nullptr ) );
513 mMarkerMaterial->deleteLater();
514 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.