QGIS API Documentation 4.1.0-Master (9af12b5a203)
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 "qgspoint3dsymbol.h"
23#include "qgspolygon3dsymbol.h"
24
25#include <QColor>
26#include <QPainter>
27#include <QPainterPath>
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
33{
34 QColor color = QColor();
35
36 if ( !symbol )
37 {
38 return color;
39 }
40
41 QgsAbstractMaterialSettings *materialSettings = symbol->materialSettings();
42 if ( materialSettings )
43 {
44 color = materialSettings->averageColor();
45 }
46 else
47 {
48 QgsDebugError( u"Qgs3DSymbolUtils::vectorMaterialAverageColor: unable to retrieve material from symbol"_s );
49 }
50
51 return color;
52}
53
54QIcon Qgs3DSymbolUtils::vectorSymbolPreviewIcon( const QgsAbstract3DSymbol *symbol, const QSize &size, const QgsScreenProperties &screen, int padding )
55{
56 if ( !symbol || ( symbol->type() != "line"_L1 && symbol->type() == "point"_L1 && symbol->type() == "polygon"_L1 ) )
57 {
58 QgsDebugError( u"A vector symbol is expected by the Qgs3DSymbolUtils::vectorSymbolPreviewIcon function"_s );
59 return QIcon();
60 }
61
62 const double devicePixelRatio = screen.isValid() ? screen.devicePixelRatio() : 1;
63 QPixmap pixmap( size * devicePixelRatio );
64 pixmap.setDevicePixelRatio( devicePixelRatio );
65 pixmap.fill( Qt::transparent );
66
67 QPainter painter( &pixmap );
68 painter.setRenderHint( QPainter::Antialiasing );
69 painter.setPen( Qt::NoPen );
70
71 const QColor baseColor = Qgs3DSymbolUtils::vectorSymbolAverageColor( symbol );
72 painter.setBrush( QBrush( baseColor ) );
73
74 if ( symbol->type() == "line"_L1 )
75 {
76 // For lines, the icon size depends on the width of the line
77 // draw a line
78 const QgsLine3DSymbol *lineSymbol = dynamic_cast<const QgsLine3DSymbol *>( symbol );
79 const int lineHeight = std::min( static_cast<int>( lineSymbol->width() ), size.height() - 2 * padding );
80 const int y = ( size.height() - lineHeight ) / 2;
81 painter.drawRect( padding, y, size.width() - 2 * padding, lineHeight );
82 }
83 else if ( symbol->type() == "point"_L1 )
84 {
85 // For points, the icon size depends on the shape of the symbol
86 const QgsPoint3DSymbol *pointSymbol = dynamic_cast<const QgsPoint3DSymbol *>( symbol );
87 switch ( pointSymbol->shape() )
88 {
90 {
91 // draw a projected cone
92 float bottomRadius = pointSymbol->shapeProperty( u"bottomRadius"_s ).toFloat();
93 float topRadius = 2 * pointSymbol->shapeProperty( u"topRadius"_s ).toFloat();
94 float length = pointSymbol->shapeProperty( u"length"_s ).toFloat();
95
96 const float maxRadius = static_cast<float>( size.width() ) / 2.0f - static_cast<float>( padding );
97 const float maxLength = static_cast<float>( size.height() ) - 2.0f * static_cast<float>( padding );
98
99 bottomRadius = std::min( bottomRadius, maxRadius );
100 topRadius = std::min( topRadius, maxRadius );
101 length = std::min( length, maxLength );
102
103 const float centerX = static_cast<float>( size.width() ) / 2.0f;
104 const float availableHeight = static_cast<float>( size.height() - 2 * padding );
105 const float topY = static_cast<float>( padding ) + ( availableHeight - length ) / 2.0f;
106 const float bottomY = topY + length;
107
108 QPainterPath path;
109 const QPointF topLeft( centerX - topRadius, topY );
110 const QPointF topRight( centerX + topRadius, topY );
111 const QPointF bottomLeft( centerX - bottomRadius, bottomY );
112 const QPointF bottomRight( centerX + bottomRadius, bottomY );
113
114 path.moveTo( topLeft );
115 path.lineTo( bottomLeft );
116 path.lineTo( bottomRight );
117 path.lineTo( topRight );
118 path.closeSubpath();
119 painter.fillPath( path, painter.brush() );
120 break;
121 }
124 {
125 // draw a rectangle
126 const int pointSize = static_cast<int>( pointSymbol->shapeProperty( u"size"_s ).toFloat() );
127 const int rectSize = std::min( std::min( pointSize, size.height() ), size.width() ) - 2 * padding;
128 const int rectX = ( size.width() - rectSize ) / 2;
129 const int rectY = ( size.height() - rectSize ) / 2;
130 painter.drawRect( rectX, rectY, rectSize, rectSize );
131 break;
132 }
134 {
135 // draw a projected cylinder
136 float radius = pointSymbol->shapeProperty( u"radius"_s ).toFloat();
137 float length = pointSymbol->shapeProperty( u"length"_s ).toFloat();
138 float centerX = static_cast<float>( size.width() ) / 2.0f;
139
140 float maxRadius = static_cast<float>( size.width() ) / 2.0f - static_cast<float>( padding );
141 float maxLength = static_cast<float>( size.height() - 2 * padding );
142 radius = std::min( radius, maxRadius );
143 length = std::min( length, maxLength );
144
145 float availableHeight = static_cast<float>( size.height() - 2 * padding );
146 float topY = static_cast<float>( padding ) + ( availableHeight - length ) / 2.0f;
147 float bottomY = topY + length;
148
149 QPainterPath path;
150 QPointF topLeft( centerX - radius, topY );
151 QPointF topRight( centerX + radius, topY );
152 QPointF bottomLeft( centerX - radius, bottomY );
153 QPointF bottomRight( centerX + radius, bottomY );
154
155 path.moveTo( topLeft );
156 path.lineTo( bottomLeft );
157 path.lineTo( bottomRight );
158 path.lineTo( topRight );
159 path.closeSubpath();
160
161 painter.fillPath( path, painter.brush() );
162 painter.drawPath( path );
163 break;
164 }
166 {
167 // draw a circle
168 const float pointSize = 2 * pointSymbol->shapeProperty( u"radius"_s ).toFloat();
169 const int diameter = std::min( std::min( static_cast<int>( pointSize ), size.width() ), size.height() ) - 2 * padding;
170 const int x = ( size.width() - diameter ) / 2;
171 const int y = ( size.height() - diameter ) / 2;
172 painter.drawEllipse( x, y, diameter, diameter );
173 break;
174 }
176 {
177 // draw a projected torus
178 float radius = pointSymbol->shapeProperty( u"radius"_s ).toFloat();
179 float minorRadius = pointSymbol->shapeProperty( u"minorRadius"_s ).toFloat();
180
181 float maxRadius = std::min( static_cast<float>( size.width() ), static_cast<float>( size.height() ) ) / 2.0f - static_cast<float>( padding );
182 radius = std::min( radius, maxRadius );
183 minorRadius = std::min( minorRadius, radius );
184
185 // Exterior ellipse
186 const float centerX = static_cast<float>( size.width() ) / 2.0f;
187 const float centerY = static_cast<float>( size.height() ) / 2.0f;
188 painter.drawEllipse( QPointF( centerX, centerY ), radius, radius );
189
190 // Interior ellipse
191 painter.save();
192 painter.setCompositionMode( QPainter::CompositionMode_Clear );
193 painter.drawEllipse( QPointF( centerX, centerY ), minorRadius, minorRadius );
194 painter.restore();
195 break;
196 }
200 {
201 // fallback - draw a rectangle
202 const int shapeSize = 10;
203 const int rectSize = std::min( std::min( shapeSize, size.height() ), size.width() ) - 2 * padding;
204 const int rectX = ( size.width() - rectSize ) / 2;
205 const int rectY = ( size.height() - rectSize ) / 2;
206 painter.drawRect( rectX, rectY, rectSize, rectSize );
207 break;
208 }
209 }
210 }
211 else if ( symbol->type() == "polygon"_L1 )
212 {
213 // draw a rectangle
214 const QgsPolygon3DSymbol *polygonSymbol = dynamic_cast<const QgsPolygon3DSymbol *>( symbol );
215 if ( polygonSymbol->edgesEnabled() )
216 {
217 painter.setPen( QPen( polygonSymbol->edgeColor(), polygonSymbol->edgeWidth() ) );
218 }
219 painter.drawRect( padding, padding, size.width() - 2 * padding, size.height() - 2 * padding );
220 }
221
222 painter.end();
223 return QIcon( pixmap );
224}
225
227{
228 if ( !symbol )
229 {
230 return false;
231 }
232
233 bool colorSet = false;
234 QgsAbstractMaterialSettings *materialSettings = symbol->materialSettings();
235 if ( materialSettings )
236 {
237 materialSettings->setColorsFromBase( baseColor );
238 colorSet = true;
239 }
240 else
241 {
242 QgsDebugError( u"Qgs3DSymbolUtils::setVectorSymbolBaseColor: unable to retrieve material from symbol"_s );
243 }
244
245 return colorSet;
246}
247
249{
250 bool copied = false;
251
252 if ( fromSymbol && toSymbol )
253 {
254 toSymbol->setMaterialSettings( fromSymbol->materialSettings()->clone() );
255 copied = true;
256 }
257 else
258 {
259 QgsDebugError( u"Qgs3DSymbolUtils::copyVectorSymbolMaterial: unable to retrieve material from symbols"_s );
260 }
261
262 return copied;
263}
@ Plane
Flat plane.
Definition qgis.h:4326
@ Cylinder
Cylinder.
Definition qgis.h:4321
@ Torus
Torus.
Definition qgis.h:4325
@ ExtrudedText
Extruded text.
Definition qgis.h:4327
@ Model
Model.
Definition qgis.h:4328
@ Sphere
Sphere.
Definition qgis.h:4322
@ Billboard
Billboard.
Definition qgis.h:4329
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).
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:59