QGIS API Documentation 4.3.0-Master (ca159e4aeaf)
Loading...
Searching...
No Matches
qgs3dsymbolutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgs3dsymbolutils.cpp
3 --------------------------------------
4 Date : January 2026
5 Copyright : (C) 2026 by Jean Felder
6 Email : jean dot felder at oslandia dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgs3dsymbolutils.h"
17
18#include "qgsabstract3dsymbol.h"
20#include "qgsline3dsymbol.h"
21#include "qgslogger.h"
22#include "qgspainting.h"
23#include "qgspoint3dsymbol.h"
24#include "qgspolygon3dsymbol.h"
25#include "qgsrendercontext.h"
26
27#include <QColor>
28#include <QPainter>
29#include <QPainterPath>
30#include <QString>
31
32using namespace Qt::StringLiterals;
33
35{
36 QColor color = QColor();
37
38 if ( !symbol )
39 {
40 return color;
41 }
42
43 QgsAbstractMaterialSettings *materialSettings = symbol->materialSettings();
44 if ( materialSettings )
45 {
46 color = materialSettings->averageColor();
47 }
48 else
49 {
50 QgsDebugError( u"Qgs3DSymbolUtils::vectorMaterialAverageColor: unable to retrieve material from symbol"_s );
51 }
52
53 return color;
54}
55
56QIcon Qgs3DSymbolUtils::vectorSymbolPreviewIcon( const QgsAbstract3DSymbol *symbol, const QSize &size, const QgsScreenProperties &screen, int padding )
57{
58 if ( !symbol || ( symbol->type() != "line"_L1 && symbol->type() == "point"_L1 && symbol->type() == "polygon"_L1 ) )
59 {
60 QgsDebugError( u"A vector symbol is expected by the Qgs3DSymbolUtils::vectorSymbolPreviewIcon function"_s );
61 return QIcon();
62 }
63
64 const double devicePixelRatio = screen.isValid() ? screen.devicePixelRatio() : 1;
65 QPixmap pixmap( size * devicePixelRatio );
66 pixmap.setDevicePixelRatio( devicePixelRatio );
67 pixmap.fill( Qt::transparent );
68
69 QPainter painter( &pixmap );
70 painter.setRenderHint( QPainter::Antialiasing );
71 painter.setPen( Qt::NoPen );
72
73 const QColor baseColor = Qgs3DSymbolUtils::vectorSymbolAverageColor( symbol );
74 painter.setBrush( QBrush( baseColor ) );
75
76 if ( symbol->type() == "line"_L1 )
77 {
78 // For lines, the icon size depends on the width of the line
79 // draw a line
80 const QgsLine3DSymbol *lineSymbol = dynamic_cast<const QgsLine3DSymbol *>( symbol );
81 const int lineHeight = std::min( static_cast<int>( lineSymbol->width() ), size.height() - 2 * padding );
82 const int y = ( size.height() - lineHeight ) / 2;
83 painter.drawRect( padding, y, size.width() - 2 * padding, lineHeight );
84 }
85 else if ( symbol->type() == "point"_L1 )
86 {
87 // For points, the icon size depends on the shape of the symbol
88 const QgsPoint3DSymbol *pointSymbol = dynamic_cast<const QgsPoint3DSymbol *>( symbol );
89 switch ( pointSymbol->shape() )
90 {
92 {
93 // draw a projected cone
94 float bottomRadius = pointSymbol->shapeProperty( u"bottomRadius"_s ).toFloat();
95 float topRadius = 2 * pointSymbol->shapeProperty( u"topRadius"_s ).toFloat();
96 float length = pointSymbol->shapeProperty( u"length"_s ).toFloat();
97
98 const float maxRadius = static_cast<float>( size.width() ) / 2.0f - static_cast<float>( padding );
99 const float maxLength = static_cast<float>( size.height() ) - 2.0f * static_cast<float>( padding );
100
101 bottomRadius = std::min( bottomRadius, maxRadius );
102 topRadius = std::min( topRadius, maxRadius );
103 length = std::min( length, maxLength );
104
105 const float centerX = static_cast<float>( size.width() ) / 2.0f;
106 const float availableHeight = static_cast<float>( size.height() - 2 * padding );
107 const float topY = static_cast<float>( padding ) + ( availableHeight - length ) / 2.0f;
108 const float bottomY = topY + length;
109
110 QPainterPath path;
111 const QPointF topLeft( centerX - topRadius, topY );
112 const QPointF topRight( centerX + topRadius, topY );
113 const QPointF bottomLeft( centerX - bottomRadius, bottomY );
114 const QPointF bottomRight( centerX + bottomRadius, bottomY );
115
116 path.moveTo( topLeft );
117 path.lineTo( bottomLeft );
118 path.lineTo( bottomRight );
119 path.lineTo( topRight );
120 path.closeSubpath();
121 painter.fillPath( path, painter.brush() );
122 break;
123 }
126 {
127 // draw a rectangle
128 const int pointSize = static_cast<int>( pointSymbol->shapeProperty( u"size"_s ).toFloat() );
129 const int rectSize = std::min( std::min( pointSize, size.height() ), size.width() ) - 2 * padding;
130 const int rectX = ( size.width() - rectSize ) / 2;
131 const int rectY = ( size.height() - rectSize ) / 2;
132 painter.drawRect( rectX, rectY, rectSize, rectSize );
133 break;
134 }
136 {
137 // draw a projected cylinder
138 float radius = pointSymbol->shapeProperty( u"radius"_s ).toFloat();
139 float length = pointSymbol->shapeProperty( u"length"_s ).toFloat();
140 float centerX = static_cast<float>( size.width() ) / 2.0f;
141
142 float maxRadius = static_cast<float>( size.width() ) / 2.0f - static_cast<float>( padding );
143 float maxLength = static_cast<float>( size.height() - 2 * padding );
144 radius = std::min( radius, maxRadius );
145 length = std::min( length, maxLength );
146
147 float availableHeight = static_cast<float>( size.height() - 2 * padding );
148 float topY = static_cast<float>( padding ) + ( availableHeight - length ) / 2.0f;
149 float bottomY = topY + length;
150
151 QPainterPath path;
152 QPointF topLeft( centerX - radius, topY );
153 QPointF topRight( centerX + radius, topY );
154 QPointF bottomLeft( centerX - radius, bottomY );
155 QPointF bottomRight( centerX + radius, bottomY );
156
157 path.moveTo( topLeft );
158 path.lineTo( bottomLeft );
159 path.lineTo( bottomRight );
160 path.lineTo( topRight );
161 path.closeSubpath();
162
163 painter.fillPath( path, painter.brush() );
164 painter.drawPath( path );
165 break;
166 }
168 {
169 // draw a circle
170 const float pointSize = 2 * pointSymbol->shapeProperty( u"radius"_s ).toFloat();
171 const int diameter = std::min( std::min( static_cast<int>( pointSize ), size.width() ), size.height() ) - 2 * padding;
172 const int x = ( size.width() - diameter ) / 2;
173 const int y = ( size.height() - diameter ) / 2;
174 painter.drawEllipse( x, y, diameter, diameter );
175 break;
176 }
178 {
179 // draw a projected torus
180 float radius = pointSymbol->shapeProperty( u"radius"_s ).toFloat();
181 float minorRadius = pointSymbol->shapeProperty( u"minorRadius"_s ).toFloat();
182
183 float maxRadius = std::min( static_cast<float>( size.width() ), static_cast<float>( size.height() ) ) / 2.0f - static_cast<float>( padding );
184 radius = std::min( radius, maxRadius );
185 minorRadius = std::min( minorRadius, radius );
186
187 // Exterior ellipse
188 const float centerX = static_cast<float>( size.width() ) / 2.0f;
189 const float centerY = static_cast<float>( size.height() ) / 2.0f;
190 painter.drawEllipse( QPointF( centerX, centerY ), radius, radius );
191
192 // Interior ellipse
193 QgsScopedQPainterState painterState( &painter );
194 painter.setCompositionMode( QPainter::CompositionMode_Clear );
195 painter.drawEllipse( QPointF( centerX, centerY ), minorRadius, minorRadius );
196 break;
197 }
201 {
202 // fallback - draw a rectangle
203 const int shapeSize = 10;
204 const int rectSize = std::min( std::min( shapeSize, size.height() ), size.width() ) - 2 * padding;
205 const int rectX = ( size.width() - rectSize ) / 2;
206 const int rectY = ( size.height() - rectSize ) / 2;
207 painter.drawRect( rectX, rectY, rectSize, rectSize );
208 break;
209 }
210 }
211 }
212 else if ( symbol->type() == "polygon"_L1 )
213 {
214 // draw a rectangle
215 const QgsPolygon3DSymbol *polygonSymbol = dynamic_cast<const QgsPolygon3DSymbol *>( symbol );
216 if ( polygonSymbol->edgesEnabled() )
217 {
218 painter.setPen( QPen( polygonSymbol->edgeColor(), polygonSymbol->edgeWidth() ) );
219 }
220 painter.drawRect( padding, padding, size.width() - 2 * padding, size.height() - 2 * padding );
221 }
222
223 painter.end();
224 return QIcon( pixmap );
225}
226
228{
229 if ( !symbol )
230 {
231 return false;
232 }
233
234 bool colorSet = false;
235 QgsAbstractMaterialSettings *materialSettings = symbol->materialSettings();
236 if ( materialSettings )
237 {
238 materialSettings->setColorsFromBase( baseColor );
239 colorSet = true;
240 }
241 else
242 {
243 QgsDebugError( u"Qgs3DSymbolUtils::setVectorSymbolBaseColor: unable to retrieve material from symbol"_s );
244 }
245
246 return colorSet;
247}
248
250{
251 bool copied = false;
252
253 if ( fromSymbol && toSymbol )
254 {
255 toSymbol->setMaterialSettings( fromSymbol->materialSettings()->clone() );
256 copied = true;
257 }
258 else
259 {
260 QgsDebugError( u"Qgs3DSymbolUtils::copyVectorSymbolMaterial: unable to retrieve material from symbols"_s );
261 }
262
263 return copied;
264}
@ Plane
Flat plane.
Definition qgis.h:4437
@ Cylinder
Cylinder.
Definition qgis.h:4432
@ Torus
Torus.
Definition qgis.h:4436
@ ExtrudedText
Extruded text.
Definition qgis.h:4438
@ Model
Model.
Definition qgis.h:4439
@ Sphere
Sphere.
Definition qgis.h:4433
@ Billboard
Billboard.
Definition qgis.h:4440
static QColor vectorSymbolAverageColor(const QgsAbstract3DSymbol *symbol)
Computes an approximate color from a 3D vector symbol.
static bool copyVectorSymbolMaterial(const QgsAbstract3DSymbol *fromSymbol, QgsAbstract3DSymbol *toSymbol)
Copies the material properties of a vector 3D symbol from one symbol to another.
static QIcon vectorSymbolPreviewIcon(const QgsAbstract3DSymbol *symbol, const QSize &size, const QgsScreenProperties &screen, int padding)
Returns an icon preview for a 3D vector symbol.
static bool setVectorSymbolBaseColor(QgsAbstract3DSymbol *symbol, const QColor &baseColor)
Sets the base color of the material settings associated with a 3D vector symbol.
Abstract base class for 3D symbols that are used by VectorLayer3DRenderer objects.
virtual void setMaterialSettings(QgsAbstractMaterialSettings *materialSettings)=0
Sets the material settings used for shading of the symbol.
virtual QgsAbstractMaterialSettings * materialSettings() const
Returns the 3D material settings associated with this symbol.
virtual QString type() const =0
Returns identifier of symbol type. Each 3D symbol implementation should return a different type.
Abstract base class for material settings.
virtual QgsAbstractMaterialSettings * clone() const =0
Clones the material settings.
virtual QColor averageColor() const =0
Returns an approximate color representing the blended material color.
virtual void setColorsFromBase(const QColor &baseColor)=0
Decomposes a base color into the material's color components, and sets the material's colors accordin...
3D symbol that draws linestring geometries as planar polygons (created from lines using a buffer with...
float width() const
Returns width of the line symbol (in map units).
3D symbol that draws point geometries as 3D objects using one of the predefined shapes.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
3D symbol that draws polygon geometries as planar polygons, optionally extruded (with added walls).
QColor edgeColor() const
Returns edge lines color.
bool edgesEnabled() const
Returns whether edge highlighting is enabled.
float edgeWidth() const
Returns width of edge lines (in pixels).
Scoped object for saving and restoring a QPainter object's state.
Stores properties relating to a screen.
double devicePixelRatio() const
Returns the ratio between physical pixels and device-independent pixels for the screen.
bool isValid() const
Returns true if the properties are valid.
#define QgsDebugError(str)
Definition qgslogger.h:71