QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgstextureatlasgenerator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgstextureatlasgenerator.cpp
3 --------------------------------------
4 Date : September 2025
5 Copyright : (C) 2025 by Nyall Dawson
6 Email : nyall dot dawson at gmail 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
17
18#include "qgscolorrampimpl.h"
19
20#include <QPainter>
21
22// rectpack2D library
23#include <finders_interface.h>
24
26
27class QgsTextureRect
28{
29 public:
30 QgsTextureRect( const rectpack2D::rect_xywh &rect, const QImage &image = QImage() )
31 : rect( rect )
32 , image( image )
33 {
34 }
35
36 // get_rect must be implemented for rectpack2D compatibility:
37 auto &get_rect()
38 {
39 return rect;
40 }
41 const auto &get_rect() const
42 {
43 return rect;
44 }
45
46 QRect asQRect() const
47 {
48 return QRect( rect.x, rect.y, rect.w, rect.h );
49 }
50
51 rectpack2D::rect_xywh rect;
52 QImage image;
53};
54
56
57
62
64{
65 return static_cast< int >( mRects.size() );
66}
67
68QRect QgsTextureAtlas::rect( int id ) const
69{
70 return mRects[id].asQRect();
71}
72
74{
75 if ( mAtlasSize.isEmpty() )
76 return QImage();
77
78 QImage res( mAtlasSize, QImage::Format_ARGB32_Premultiplied );
79 res.fill( Qt::transparent );
80
81 QPainter painter( &res );
82 for ( const QgsTextureRect &rect : mRects )
83 {
84 if ( !rect.image.isNull() )
85 {
86 painter.drawImage( rect.asQRect(), rect.image );
87 }
88 }
89 painter.end();
90
91 return res;
92}
93
95{
96 if ( mAtlasSize.isEmpty() )
97 return QImage();
98
99 QImage res( mAtlasSize, QImage::Format_ARGB32_Premultiplied );
100 res.fill( Qt::transparent );
101
102 QPainter painter( &res );
103 painter.setPen( Qt::NoPen );
105 ramp.setTotalColorCount( static_cast< int >( mRects.size() ) );
106 double index = 0;
107 for ( const QgsTextureRect &rect : mRects )
108 {
109 const QColor color = ramp.color( index / ( static_cast< int >( mRects.size() ) - 1 ) );
110 index += 1;
111 painter.setBrush( QBrush( color ) );
112 painter.drawRect( rect.asQRect() );
113 }
114 painter.end();
115
116 return res;
117}
118
119
120//
121// QgsTextureAtlasGenerator
122//
123
124QgsTextureAtlas QgsTextureAtlasGenerator::createFromRects( const QVector<QRect> &rectangles, int maxSide )
125{
126 std::vector< QgsTextureRect > rects;
127 rects.reserve( rectangles.size() );
128 for ( const QRect &rect : rectangles )
129 {
130 rects.emplace_back( QgsTextureRect( rectpack2D::rect_xywh( 0, 0, rect.width(), rect.height() ) ) );
131 }
132 return generateAtlas( std::move( rects ), maxSide );
133}
134
135QgsTextureAtlas QgsTextureAtlasGenerator::createFromImages( const QVector<QImage> &images, int maxSide )
136{
137 std::vector< QgsTextureRect > rects;
138 rects.reserve( images.size() );
139 for ( const QImage &image : images )
140 {
141 rects.emplace_back( QgsTextureRect( rectpack2D::rect_xywh( 0, 0, image.width(), image.height() ), image ) );
142 }
143 return generateAtlas( std::move( rects ), maxSide );
144}
145
146QgsTextureAtlas QgsTextureAtlasGenerator::generateAtlas( std::vector< QgsTextureRect > rects, int maxSide )
147{
148 using spacesType = rectpack2D::empty_spaces<false, rectpack2D::default_empty_spaces>;
149
150 bool result = true;
151 auto reportSuccessful = []( rectpack2D::rect_xywh & ) {
152 return rectpack2D::callback_result::CONTINUE_PACKING;
153 };
154
155 auto reportUnsuccessful = [&result]( rectpack2D::rect_xywh & ) {
156 result = false;
157 return rectpack2D::callback_result::ABORT_PACKING;
158 };
159
160 const auto discardStep = -4;
161
162 auto byWidth = []( const rectpack2D::rect_xywh *a, const rectpack2D::rect_xywh *b ) {
163 return a->w > b->w;
164 };
165
166 const rectpack2D::rect_wh resultSize = rectpack2D::find_best_packing<spacesType>(
167 rects,
168 rectpack2D::make_finder_input(
169 maxSide,
170 discardStep,
171 reportSuccessful,
172 reportUnsuccessful,
173 rectpack2D::flipping_option::DISABLED
174 ),
175 byWidth
176 );
177
178 if ( !result )
179 return QgsTextureAtlas();
180
181 QgsTextureAtlas res;
182 res.mRects = std::move( rects );
183 res.mAtlasSize = QSize( resultSize.w, resultSize.h );
184 return res;
185}
A color ramp consisting of random colors, constrained within component ranges.
virtual void setTotalColorCount(int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QColor color(double value) const override
Returns the color corresponding to a specified value.
static QgsTextureAtlas createFromRects(const QVector< QRect > &rectangles, int maxSide=1000)
Creates a texture atlas for a set of rectangles.
static QgsTextureAtlas createFromImages(const QVector< QImage > &images, int maxSide=1000)
Creates a texture atlas for a set of images.
Encapsulates a texture atlas.
int count() const
Returns the number of textures in the atlas.
QgsTextureAtlas & operator=(const QgsTextureAtlas &other)
QRect rect(int index) const
Returns the packed rectangle for the texture with the specified index.
QImage renderDebugTexture() const
Renders a debug texture.
QImage renderAtlasTexture() const
Renders the combined texture atlas, containing all source images.