QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 // get_rect must be implemented for rectpack2D compatibility:
36 auto &get_rect() { return rect; }
37 const auto &get_rect() const { return rect; }
38
39 QRect asQRect() const { return QRect( rect.x, rect.y, rect.w, rect.h ); }
40
41 rectpack2D::rect_xywh rect;
42 QImage image;
43};
44
46
47
52
54{
55 return static_cast< int >( mRects.size() );
56}
57
58QRect QgsTextureAtlas::rect( int id ) const
59{
60 return mRects[id].asQRect();
61}
62
64{
65 if ( mAtlasSize.isEmpty() )
66 return QImage();
67
68 QImage res( mAtlasSize, QImage::Format_ARGB32_Premultiplied );
69 res.fill( Qt::transparent );
70
71 QPainter painter( &res );
72 for ( const QgsTextureRect &rect : mRects )
73 {
74 if ( !rect.image.isNull() )
75 {
76 painter.drawImage( rect.asQRect(), rect.image );
77 }
78 }
79 painter.end();
80
81 return res;
82}
83
85{
86 if ( mAtlasSize.isEmpty() )
87 return QImage();
88
89 QImage res( mAtlasSize, QImage::Format_ARGB32_Premultiplied );
90 res.fill( Qt::transparent );
91
92 QPainter painter( &res );
93 painter.setPen( Qt::NoPen );
95 ramp.setTotalColorCount( static_cast< int >( mRects.size() ) );
96 double index = 0;
97 for ( const QgsTextureRect &rect : mRects )
98 {
99 const QColor color = ramp.color( index / ( static_cast< int >( mRects.size() ) - 1 ) );
100 index += 1;
101 painter.setBrush( QBrush( color ) );
102 painter.drawRect( rect.asQRect() );
103 }
104 painter.end();
105
106 return res;
107}
108
109
110//
111// QgsTextureAtlasGenerator
112//
113
114QgsTextureAtlas QgsTextureAtlasGenerator::createFromRects( const QVector<QRect> &rectangles, int maxSide )
115{
116 std::vector< QgsTextureRect > rects;
117 rects.reserve( rectangles.size() );
118 for ( const QRect &rect : rectangles )
119 {
120 rects.emplace_back( QgsTextureRect( rectpack2D::rect_xywh( 0, 0, rect.width(), rect.height() ) ) );
121 }
122 return generateAtlas( std::move( rects ), maxSide );
123}
124
125QgsTextureAtlas QgsTextureAtlasGenerator::createFromImages( const QVector<QImage> &images, int maxSide )
126{
127 std::vector< QgsTextureRect > rects;
128 rects.reserve( images.size() );
129 for ( const QImage &image : images )
130 {
131 rects.emplace_back( QgsTextureRect( rectpack2D::rect_xywh( 0, 0, image.width(), image.height() ), image ) );
132 }
133 return generateAtlas( std::move( rects ), maxSide );
134}
135
136QgsTextureAtlas QgsTextureAtlasGenerator::generateAtlas( std::vector< QgsTextureRect > rects, int maxSide )
137{
138 using spacesType = rectpack2D::empty_spaces<false, rectpack2D::default_empty_spaces>;
139
140 bool result = true;
141 auto reportSuccessful = []( rectpack2D::rect_xywh & ) { return rectpack2D::callback_result::CONTINUE_PACKING; };
142
143 auto reportUnsuccessful = [&result]( rectpack2D::rect_xywh & ) {
144 result = false;
145 return rectpack2D::callback_result::ABORT_PACKING;
146 };
147
148 const auto discardStep = -4;
149
150 auto byWidth = []( const rectpack2D::rect_xywh *a, const rectpack2D::rect_xywh *b ) { return a->w > b->w; };
151
152 const rectpack2D::rect_wh resultSize
153 = rectpack2D::find_best_packing<spacesType>( rects, rectpack2D::make_finder_input( maxSide, discardStep, reportSuccessful, reportUnsuccessful, rectpack2D::flipping_option::DISABLED ), byWidth );
154
155 if ( !result )
156 return QgsTextureAtlas();
157
158 QgsTextureAtlas res;
159 res.mRects = std::move( rects );
160 res.mAtlasSize = QSize( resultSize.w, resultSize.h );
161 return res;
162}
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.