Marble

GeoDataIconStyle.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Murad Tagirov <tmurad@gmail.com>
4//
5
6
7#include "GeoDataIconStyle.h"
8
9#include <QUrl>
10
11#include "MarbleDirs.h"
12#include "MarbleDebug.h"
13#include "RemoteIconLoader.h"
14
15#include "GeoDataTypes.h"
16
17#include <QImageReader>
18
19namespace Marble
20{
21
22class GeoDataIconStylePrivate
23{
24 public:
25 GeoDataIconStylePrivate()
26 : m_scale( 1.0 ),
27 m_size(0, 0),
28 m_aspectRatioMode(Qt::KeepAspectRatio),
29 m_iconPath(),
30 m_heading( 0 )
31 {
32 }
33
34 GeoDataIconStylePrivate( const QString& iconPath, const QPointF &hotSpot )
35 : m_scale( 1.0 ),
36 m_size(0, 0),
37 m_aspectRatioMode(Qt::KeepAspectRatio),
38 m_iconPath( iconPath ),
39 m_hotSpot( hotSpot ),
40 m_heading( 0 )
41 {
42 }
43
44 RemoteIconLoader* remoteIconLoader() const
45 {
46 static RemoteIconLoader *remoteIconLoader = new RemoteIconLoader();
47 return remoteIconLoader;
48 }
49
50 QSize scaledSize(const QSize &size) const
51 {
52 QSize iconSize = size.isNull() ? m_icon.size() : size;
53 // Scaling the placemark's icon based on its size, scale, and maximum icon size.
54 if ( iconSize.width()*m_scale > s_maximumIconSize.width()
55 || iconSize.height()*m_scale > s_maximumIconSize.height() ) {
56 iconSize.scale( s_maximumIconSize, Qt::KeepAspectRatio );
57 }
58 else if ( iconSize.width()*m_scale < s_minimumIconSize.width()
59 || iconSize.height()*m_scale < s_minimumIconSize.width() ) {
60 iconSize.scale( s_minimumIconSize, Qt::KeepAspectRatio );
61 }
62 else {
63 iconSize *= m_scale;
64 }
65
66 return QSize(iconSize.width() - iconSize.width() % 2,
67 iconSize.height() - iconSize.height() % 2);
68 }
69
70 QImage loadIcon(const QString &path, const QSize &size) const
71 {
72 if (!path.isEmpty()) {
73 // Icons from the local file system
74 if (!size.isNull()) {
75 QImageReader imageReader;
76 imageReader.setFileName(path);
77 auto const imageSize = imageReader.size();
78 auto const finalSize = imageSize.scaled(size, m_aspectRatioMode);
79 imageReader.setScaledSize(finalSize);
80 QImage icon = imageReader.read();
81 if (icon.isNull()) {
82 mDebug() << "GeoDataIconStyle: Failed to read image " << path << ": " << imageReader.errorString();
83 }
84 return icon;
85 }
86 QImage icon = QImage(path);
87 if (!icon.isNull()) {
88 return icon;
89 }
90 }
91
92 if(QUrl(m_iconPath).isValid() ) {
93 // if image is not found on disk, check whether the icon is
94 // at remote location. If yes then go for remote icon loading
95 return remoteIconLoader()->load(QUrl(m_iconPath));
96 }
97
98 mDebug() << "Unable to open style icon at: " << path;
99 return QImage();
100 }
101
102 float m_scale;
103
104 QImage m_icon;
105 QSize m_size;
106 Qt::AspectRatioMode m_aspectRatioMode;
107 QImage m_scaledIcon;
108 QString m_iconPath;
109 GeoDataHotSpot m_hotSpot;
110 int m_heading;
111};
112
113GeoDataIconStyle::GeoDataIconStyle() :
114 d( new GeoDataIconStylePrivate() )
115{
116}
117
118GeoDataIconStyle::GeoDataIconStyle( const GeoDataIconStyle& other ) :
119 GeoDataColorStyle( other ), d( new GeoDataIconStylePrivate( *other.d ) )
120{
121}
122
123GeoDataIconStyle::GeoDataIconStyle( const QString& iconPath, const QPointF &hotSpot ) :
124 d( new GeoDataIconStylePrivate( iconPath, hotSpot ) )
125{
126}
127
128GeoDataIconStyle::~GeoDataIconStyle()
129{
130 delete d;
131}
132
133GeoDataIconStyle& GeoDataIconStyle::operator=( const GeoDataIconStyle& other )
134{
135 GeoDataColorStyle::operator=( other );
136 *d = *other.d;
137 return *this;
138}
139
140bool GeoDataIconStyle::operator==( const GeoDataIconStyle &other ) const
141{
142 if ( GeoDataColorStyle::operator!=( other ) ) {
143 return false;
144 }
145
146 return d->m_scale == other.d->m_scale &&
147 d->m_icon == other.d->m_icon &&
148 d->m_size == other.d->m_size &&
149 d->m_iconPath == other.d->m_iconPath &&
150 d->m_hotSpot == other.d->m_hotSpot &&
151 d->m_heading == other.d->m_heading;
152}
153
154bool GeoDataIconStyle::operator!=( const GeoDataIconStyle &other ) const
155{
156 return !this->operator==( other );
157}
158
159const char* GeoDataIconStyle::nodeType() const
160{
161 return GeoDataTypes::GeoDataIconStyleType;
162}
163
164void GeoDataIconStyle::setIcon(const QImage &icon)
165{
166 d->m_icon = icon;
167 d->m_scaledIcon = QImage();
168}
169
170void GeoDataIconStyle::setIconPath( const QString& filename )
171{
172 d->m_iconPath = filename;
173
174 /**
175 * Set the m_icon to be a default-constructed icon
176 * so that m_icon is null and icon() doesn't return
177 * previously loaded icon.
178 */
179 d->m_icon = QImage();
180 d->m_scaledIcon = QImage();
181}
182
183QString GeoDataIconStyle::iconPath() const
184{
185 return d->m_iconPath;
186}
187
188QImage GeoDataIconStyle::icon() const
189{
190 if ( !d->m_icon.isNull() ) {
191 return d->m_icon;
192 }
193 else if ( !d->m_iconPath.isEmpty() ) {
194 d->m_icon = d->loadIcon(resolvePath(d->m_iconPath), d->m_size);
195 return d->m_icon;
196 }
197 else
198 return QImage();
199}
200
201void GeoDataIconStyle::setHotSpot( const QPointF& hotSpot,
202 GeoDataHotSpot::Units xunits,
203 GeoDataHotSpot::Units yunits )
204{
205 d->m_hotSpot.setHotSpot( hotSpot, xunits, yunits );
206}
207
208QPointF GeoDataIconStyle::hotSpot( GeoDataHotSpot::Units &xunits, GeoDataHotSpot::Units &yunits ) const
209{
210 return d->m_hotSpot.hotSpot( xunits, yunits );
211}
212
213void GeoDataIconStyle::setSize(const QSize &size, Qt::AspectRatioMode aspectRatioMode)
214{
215 if (size == d->m_size && aspectRatioMode == d->m_aspectRatioMode) {
216 return;
217 }
218
219 d->m_aspectRatioMode = aspectRatioMode;
220 d->m_size = QSize(size.width() - size.width() % 2, size.height() - size.height() % 2);
221 if (!d->m_size.isNull() && !d->m_icon.isNull()) {
222 // Resize existing icon that cannot be restored from an image path
223 d->m_icon = d->m_icon.scaled(d->m_size);
224 } else if (!d->m_iconPath.isEmpty()) {
225 // Lazily reload the icons
226 d->m_icon = QImage();
227 d->m_scaledIcon = QImage();
228 }
229}
230
231QSize GeoDataIconStyle::size() const
232{
233 return d->m_size;
234}
235
236void GeoDataIconStyle::setScale(float scale)
237{
238 d->m_scale = scale;
239 d->m_scaledIcon = QImage();
240}
241
242float GeoDataIconStyle::scale() const
243{
244 return d->m_scale;
245}
246
247QImage GeoDataIconStyle::scaledIcon() const
248{
249 if (!d->m_scaledIcon.isNull()) {
250 return d->m_scaledIcon;
251 }
252
253 // Invalid or trivial scale
254 if (d->m_scale <= 0 || d->m_scale == 1.0) {
255 return icon();
256 }
257
258 // Try to load it
259 d->m_scaledIcon = d->loadIcon(resolvePath(d->m_iconPath), d->scaledSize(d->m_size));
260
261 if (d->m_scaledIcon.isNull()) {
262 // Direct loading failed, try to scale the icon as a last resort
263 QImage const image = icon();
264 if (!image.isNull()) {
265 QSize iconSize = d->scaledSize(image.size());
266 d->m_scaledIcon = image.scaled( iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ;
267 }
268 }
269 return d->m_scaledIcon;
270}
271
272int GeoDataIconStyle::heading() const
273{
274 return d->m_heading;
275}
276
277void GeoDataIconStyle::setHeading( int heading )
278{
279 d->m_heading = heading;
280}
281
282RemoteIconLoader *GeoDataIconStyle::remoteIconLoader() const
283{
284 return d->remoteIconLoader();
285}
286
287void GeoDataIconStyle::pack( QDataStream& stream ) const
288{
289 GeoDataColorStyle::pack( stream );
290
291 stream << d->m_scale;
292 stream << d->m_icon;
293 d->m_hotSpot.pack( stream );
294}
295
296void GeoDataIconStyle::unpack( QDataStream& stream )
297{
298 GeoDataColorStyle::unpack( stream );
299
300 stream >> d->m_scale;
301 stream >> d->m_icon;
302 d->m_hotSpot.unpack( stream );
303}
304
305}
QString path(const QString &relativePath)
bool isValid(QStringView ifopt)
Binds a QML item to a specific geodetic location in screen coordinates.
bool isNull() const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QSize size() const const
QString errorString() const const
QImage read()
void setFileName(const QString &fileName)
void setScaledSize(const QSize &size)
QSize size() const const
int height() const const
bool isNull() const const
void scale(const QSize &size, Qt::AspectRatioMode mode)
QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const const
int width() const const
bool isEmpty() const const
bool operator==(const QGraphicsApiFilter &reference, const QGraphicsApiFilter &sample)
KeepAspectRatio
SmoothTransformation
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.