41#include <Qt3DCore/QAttribute>
42#include <Qt3DCore/QBuffer>
43#include <Qt3DCore/QEntity>
44#include <Qt3DCore/QGeometry>
45#include <Qt3DRender/QGeometryRenderer>
47using namespace Qt::StringLiterals;
53 : mMapSettings( &map )
55 , mGeometryType( geometryType )
57 switch ( mGeometryType )
60 setupMarker( parentEntity );
63 setupLine( parentEntity );
64 setupMarker( parentEntity );
67 setupMarker( parentEntity );
68 setupLine( parentEntity );
69 setupPolygon( parentEntity );
73 QgsDebugError(
"Unknown GeometryType used in QgsRubberband3D" );
78void QgsRubberBand3D::setupMarker( Qt3DCore::QEntity *parentEntity )
82 mMarkerGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
83 mMarkerGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
84 mMarkerGeometryRenderer->setGeometry( mMarkerGeometry );
85 mMarkerGeometryRenderer->setVertexCount( mMarkerGeometry->count() );
87 setMarkerType( mMarkerType );
88 mMarkerEntity->addComponent( mMarkerGeometryRenderer );
90 mMarkerTransform =
new QgsGeoTransform;
91 mMarkerTransform->setOrigin( mMapSettings->origin() );
92 mMarkerEntity->addComponent( mMarkerTransform );
95void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity )
99 QgsLineVertexData dummyLineData;
100 mLineGeometry = dummyLineData.createGeometry( mLineEntity );
102 Q_ASSERT( mLineGeometry->attributes().count() == 2 );
103 mPositionAttribute = mLineGeometry->attributes().at( 0 );
104 mIndexAttribute = mLineGeometry->attributes().at( 1 );
106 mLineGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
107 mLineGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
108 mLineGeometryRenderer->setGeometry( mLineGeometry );
109 mLineGeometryRenderer->setPrimitiveRestartEnabled(
true );
110 mLineGeometryRenderer->setRestartIndexValue( 0 );
112 mLineEntity->addComponent( mLineGeometryRenderer );
114 mLineMaterial =
new QgsLineMaterial;
115 mLineMaterial->setLineWidth( mWidth );
116 mLineMaterial->setLineColor( mColor );
119 mLineMaterial->setViewportSize( mEngine->size() );
121 mLineEntity->addComponent( mLineMaterial );
123 mLineTransform =
new QgsGeoTransform;
124 mLineTransform->setOrigin( mMapSettings->origin() );
125 mLineEntity->addComponent( mLineTransform );
128void QgsRubberBand3D::setupPolygon( Qt3DCore::QEntity *parentEntity )
134 Qt3DRender::QGeometryRenderer *polygonGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
135 polygonGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
136 polygonGeometryRenderer->setGeometry( mPolygonGeometry );
137 mPolygonEntity->addComponent( polygonGeometryRenderer );
139 QColor color = mColor;
140 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
141 mPolygonMaterial =
new QgsUnlitMaterial();
142 mPolygonMaterial->setColor( color );
144 mPolygonEntity->addComponent( mPolygonMaterial );
146 mPolygonTransform =
new QgsGeoTransform;
147 mPolygonTransform->setOrigin( mMapSettings->origin() );
148 mPolygonEntity->addComponent( mPolygonTransform );
151void QgsRubberBand3D::removePoint(
int index )
156 const int vertexIndex = index < 0 ? lineString->
numPoints() - 1 + index : index;
166 const int vertexIndex = index < 0 ? lineString->
numPoints() + index : index;
177QgsRubberBand3D::~QgsRubberBand3D()
179 if ( mPolygonEntity )
181 mPolygonEntity.reset();
189 mMarkerEntity.reset();
194float QgsRubberBand3D::width()
const
199void QgsRubberBand3D::setWidth(
float width )
204 if ( isLineOrPolygon && mEdgesEnabled )
207 mLineMaterial->setLineWidth( width );
211 mMarkerSymbol->setSize( width );
212 updateMarkerMaterial();
215QColor QgsRubberBand3D::color()
const
220void QgsRubberBand3D::setColor(
const QColor color )
225 if ( mEdgesEnabled && isLineOrPolygon )
227 mLineMaterial->setLineColor( color );
230 if ( isLineOrPolygon )
232 mMarkerSymbol->setColor( color.lighter( 130 ) );
236 mMarkerSymbol->setColor( color );
239 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 && !mOutlineColor.value() )
241 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
243 updateMarkerMaterial();
247 if ( mPolygonMaterial )
248 mPolygonEntity->removeComponent( mPolygonMaterial );
250 if ( mPolygonFillEnabled )
252 QColor color = mColor;
253 color.setAlphaF( DEFAULT_POLYGON_OPACITY );
254 mPolygonMaterial =
new QgsUnlitMaterial();
255 mPolygonMaterial->setColor( color );
256 mPolygonEntity->addComponent( mPolygonMaterial );
261QColor QgsRubberBand3D::outlineColor()
const
263 return mOutlineColor;
266void QgsRubberBand3D::setOutlineColor(
const QColor color )
268 mOutlineColor = color;
270 if ( mMarkerSymbol->symbolLayerCount() > 0 && mMarkerSymbol->symbolLayer( 0 )->layerType() ==
"SimpleMarker"_L1 )
272 mMarkerSymbol->symbolLayer( 0 )->setStrokeColor( color );
274 updateMarkerMaterial();
277void QgsRubberBand3D::setMarkerType(
const MarkerType marker )
279 mMarkerType = marker;
283 const QVariantMap props {
284 { u
"color"_s, lineOrPolygon ? mColor.lighter( 130 ).name() : mColor.name() },
285 { u
"size_unit"_s, u
"pixel"_s },
286 { u
"size"_s, QString::number( lineOrPolygon ? mWidth * 3.f : mWidth ) },
287 { u
"outline_color"_s, mOutlineColor.value() ? mOutlineColor.name() : mColor.name() },
289 { u
"outline_width"_s, QString::number( lineOrPolygon ? 0.5 : 1 ) },
290 { u
"name"_s, mMarkerType == Square ? u
"square"_s : u
"circle"_s }
294 updateMarkerMaterial();
297QgsRubberBand3D::MarkerType QgsRubberBand3D::markerType()
const
302void QgsRubberBand3D::setMarkerOutlineStyle(
const Qt::PenStyle style )
304 mMarkerOutlineStyle = style;
305 setMarkerType( markerType() );
308Qt::PenStyle QgsRubberBand3D::markerOutlineStyle()
const
310 return mMarkerOutlineStyle;
313void QgsRubberBand3D::setMarkersEnabled(
const bool enable )
315 mMarkerEnabled = enable;
316 updateMarkerMaterial();
319bool QgsRubberBand3D::hasMarkersEnabled()
const
321 return mMarkerEnabled;
324void QgsRubberBand3D::setEdgesEnabled(
const bool enable )
326 mEdgesEnabled = enable;
330bool QgsRubberBand3D::hasEdgesEnabled()
const
332 return mEdgesEnabled;
335void QgsRubberBand3D::setFillEnabled(
const bool enable )
337 mPolygonFillEnabled = enable;
341bool QgsRubberBand3D::hasFillEnabled()
const
343 return mPolygonFillEnabled;
346void QgsRubberBand3D::reset()
348 mGeometry.set(
nullptr );
352void QgsRubberBand3D::addPoint(
const QgsPoint &pt )
357 const int lastVertexIndex = exteriorRing->
numPoints() - 1;
369 else if ( !mGeometry.constGet() )
371 mGeometry.set(
new QgsLineString( QVector<QgsPoint> { pt } ) );
377void QgsRubberBand3D::setGeometry(
const QgsGeometry &geometry )
379 mGeometry = geometry;
380 mGeometryType = geometry.
type();
385void QgsRubberBand3D::removeLastPoint()
390void QgsRubberBand3D::removePenultimatePoint()
395void QgsRubberBand3D::moveLastPoint(
const QgsPoint &pt )
400 const int lastVertexIndex = lineString->
numPoints() - 2;
405 const int lastVertexIndex = lineString->
numPoints() - 1;
416void QgsRubberBand3D::updateGeometry()
419 const QgsBox3D box = mGeometry.constGet() ? mGeometry.constGet()->boundingBox3D() :
QgsBox3D();
422 QgsLineVertexData lineData;
423 lineData.withAdjacency =
true;
429 const int lastVertexIndex = lineString->
numPoints() - 1;
431 lineData.addLineString( *lineString, 0,
true );
435 lineData.addLineString( *lineString, 0,
false );
441 mPositionAttribute->buffer()->setData( lineData.createVertexBuffer() );
442 mIndexAttribute->buffer()->setData( lineData.createIndexBuffer() );
443 mLineGeometryRenderer->setVertexCount(
static_cast<int>( lineData.indexes.count() ) );
444 mLineTransform->setGeoTranslation( dataOrigin );
448 lineData.vertices.pop_front();
451 if ( mHideLastMarker && !lineData.vertices.isEmpty() )
452 lineData.vertices.pop_back();
454 mMarkerGeometry->setPositions( lineData.vertices );
455 mMarkerGeometryRenderer->setVertexCount(
static_cast<int>( lineData.vertices.count() ) );
456 mMarkerTransform->setGeoTranslation( dataOrigin );
463 tessellator.
setOrigin( mMapSettings->origin() );
466 if ( !tessellator.
error().isEmpty() )
471 const QByteArray vertexBuffer = tessellator.
vertexBuffer();
472 const QByteArray indexBuffer = tessellator.
indexBuffer();
476 mPolygonGeometry->setVertexBufferData( vertexBuffer, vertexCount, QVector<QgsFeatureId>(), QVector<uint>() );
477 mPolygonGeometry->setIndexBufferData( indexBuffer, indexCount );
478 mPolygonTransform->setGeoTranslation( mMapSettings->origin() );
482 mPolygonGeometry->setVertexBufferData( QByteArray(), 0, QVector<QgsFeatureId>(), QVector<uint>() );
483 mPolygonGeometry->setIndexBufferData( QByteArray(), 0 );
488void QgsRubberBand3D::updateMarkerMaterial()
490 if ( mMarkerEnabled )
492 if ( !mMarkerMaterial )
495 mMarkerEntity->addComponent( mMarkerMaterial );
497 QObject::connect( mEngine, &
QgsAbstract3DEngine::sizeChanged, mMarkerMaterial, [material = mMarkerMaterial, engine = mEngine] { material->setViewportSize( engine->
size() ); } );
501 mMarkerMaterial->setViewportSize( mEngine->size() );
503 else if ( !mMarkerEnabled && mMarkerMaterial )
505 mMarkerEntity->removeComponent( mMarkerMaterial );
506 mMarkerMaterial->setParent(
static_cast<Qt3DCore::QEntity *
>(
nullptr ) );
507 mMarkerMaterial->deleteLater();
508 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.