Coverage Report

Created: 2025-07-11 06:33

/src/bag/api/bag_descriptor.cpp
Line
Count
Source (jump to first uncovered line)
1
2
#include "bag_descriptor.h"
3
#include "bag_exceptions.h"
4
#include "bag_layer.h"
5
#include "bag_metadata.h"
6
7
#include <algorithm>
8
#include <cctype>
9
10
11
namespace BAG {
12
13
namespace {
14
15
//! Find a descriptor by layer type and case-insensitive name.
16
/*!
17
\param inDescriptors
18
    The descriptors to search.
19
\param inType
20
    The layer type to match.
21
\param inName
22
    The case-insensitive layer name to match.
23
24
\return
25
    The found descriptor.
26
    nullptr if not found.
27
*/
28
const LayerDescriptor* getLayerDescriptor(
29
    const std::vector<std::weak_ptr<const LayerDescriptor>>& inDescriptors,
30
    LayerType inType,
31
    const std::string& inName)
32
239
{
33
239
    if (inType == Georef_Metadata && inName.empty())
34
0
        throw NameRequired{};
35
36
239
    std::string nameLower{inName};
37
239
    std::transform(begin(nameLower), end(nameLower), begin(nameLower),
38
2.58k
        [](char c) noexcept {
39
2.58k
            return static_cast<char>(std::tolower(c));
40
2.58k
        });
41
42
239
    const auto& layerDesc = std::find_if(cbegin(inDescriptors),
43
239
        cend(inDescriptors),
44
239
        [inType, &nameLower](const std::weak_ptr<const LayerDescriptor>& d) {
45
112
            if (d.expired())
46
0
                return false;
47
48
112
            auto desc = d.lock();
49
50
112
            if (desc->getLayerType() != inType)
51
112
                return false;
52
53
0
            if (nameLower.empty())
54
0
                return true;
55
56
0
            std::string foundNameLower{desc->getName()};
57
0
            std::transform(begin(foundNameLower), end(foundNameLower), begin(foundNameLower),
58
0
                [](char c) noexcept {
59
0
                    return static_cast<char>(std::tolower(c));
60
0
                });
61
62
0
            return foundNameLower == nameLower;
63
0
        });
64
239
    if (layerDesc == cend(inDescriptors))
65
239
        return {};
66
67
0
    return layerDesc->lock().get();
68
239
}
69
70
}  // namespace
71
72
//! Constructor.
73
/*!
74
\param metadata
75
    The metadata.
76
*/
77
Descriptor::Descriptor(
78
    const Metadata& metadata)
79
242
    : m_horizontalReferenceSystem(metadata.horizontalReferenceSystemAsWKT())
80
242
    , m_verticalReferenceSystem(metadata.verticalReferenceSystemAsWKT())
81
242
    , m_dims({metadata.rows(), metadata.columns()})
82
242
    , m_projectedCover({metadata.llCornerX(), metadata.llCornerY(),
83
242
        metadata.urCornerX(), metadata.urCornerY()})
84
242
    , m_origin({metadata.llCornerX(), metadata.llCornerY()})
85
242
    , m_gridSpacing({metadata.rowResolution(), metadata.columnResolution()})
86
242
{
87
242
}
88
89
//! Add a layer descriptor to this descriptor.
90
/*
91
\param inDescriptor
92
    The layer descriptor.
93
94
\return
95
    The updated descriptor.
96
*/
97
Descriptor& Descriptor::addLayerDescriptor(
98
    const LayerDescriptor& inDescriptor) &
99
239
{
100
    // Check if the layer descriptor already exists.
101
239
    if (BAG::getLayerDescriptor(m_layerDescriptors, inDescriptor.getLayerType(),
102
239
        inDescriptor.getName()))
103
0
        throw LayerExists{};
104
105
239
    m_layerDescriptors.emplace_back(inDescriptor.shared_from_this());
106
107
239
    return *this;
108
239
}
109
110
//! Retrieve BAG grid dimensions.
111
/*!
112
\return
113
    The rows and columns of the BAG.
114
*/
115
const std::tuple<uint32_t, uint32_t>& Descriptor::getDims() const & noexcept
116
48
{
117
48
    return m_dims;
118
48
}
119
120
//! Retrieve the row and column spacing/resolution of the grid.
121
/*
122
\return
123
    The row and column spacing/resolution of the grid.
124
*/
125
const std::tuple<double, double>& Descriptor::getGridSpacing() const & noexcept
126
24
{
127
24
    return m_gridSpacing;
128
24
}
129
130
//! Retrieve the horizontal reference system.
131
/*!
132
\return
133
    The horizontal reference system.
134
*/
135
const std::string& Descriptor::getHorizontalReferenceSystem() const & noexcept
136
24
{
137
24
    return m_horizontalReferenceSystem;
138
24
}
139
140
//! Retrieve a list of layer ids.
141
/*!
142
\return
143
    A list of layer ids.
144
*/
145
std::vector<uint32_t> Descriptor::getLayerIds() const noexcept
146
0
{
147
0
    std::vector<uint32_t> ids;
148
0
    ids.reserve(m_layerDescriptors.size());
149
150
0
    for (const auto& desc : m_layerDescriptors)
151
0
    {
152
0
        if (desc.expired())
153
0
            continue;
154
155
0
        auto descriptor = desc.lock();
156
0
        ids.emplace_back(descriptor->getId());
157
0
    }
158
159
0
    return ids;
160
0
}
161
162
//! Retrieve the layer descriptor by id.
163
/*!
164
\param id
165
    The layer id of the desired layer descriptor.
166
167
\return
168
    The specified layer descriptor.
169
    An exception will be thrown if the layer id does not exist.
170
*/
171
const LayerDescriptor& Descriptor::getLayerDescriptor(
172
    uint32_t id) const &
173
0
{
174
0
    const auto& desc = m_layerDescriptors.at(id);
175
0
    if (desc.expired())
176
0
        throw InvalidLayerDescriptor{};
177
178
0
    return *desc.lock();
179
0
}
180
181
//! Retrieve the specified layer descriptor by type and name.
182
/*!
183
\param type
184
    The descriptor of the layer specified by type.
185
\param name
186
    The case-insensitive name of the layer.
187
    Optional for all but georeferenced metadata layers.
188
\return
189
    The specified layer descriptor.
190
*/
191
const LayerDescriptor* Descriptor::getLayerDescriptor(
192
    LayerType type,
193
    const std::string& name) const &
194
0
{
195
0
    return BAG::getLayerDescriptor(m_layerDescriptors, type, name);
196
0
}
197
198
//! Retrieve all the layer descriptors.
199
/*!
200
\return
201
    All the layer descriptors.
202
*/
203
const std::vector<std::weak_ptr<const LayerDescriptor>>&
204
Descriptor::getLayerDescriptors() const & noexcept
205
0
{
206
0
    return m_layerDescriptors;
207
0
}
208
209
//! Retrieve all the layer types the descriptor is aware of.
210
/*!
211
\return
212
    All the unique layer types the descriptor is aware of.
213
    If multiple georeferenced metadata  layers are present, the type is only provided once.
214
*/
215
std::vector<LayerType> Descriptor::getLayerTypes() const
216
0
{
217
0
    std::vector<LayerType> types;
218
0
    types.reserve(m_layerDescriptors.size());
219
220
0
    bool addedGeorefMetadataLayer = false;
221
222
0
    for (const auto& desc : m_layerDescriptors)
223
0
    {
224
0
        if (desc.expired())
225
0
            continue;
226
227
0
        auto layerDescriptor = desc.lock();
228
229
0
        const auto type = layerDescriptor->getLayerType();
230
0
        if (type == Georef_Metadata)
231
0
        {
232
0
            if (!addedGeorefMetadataLayer)
233
0
                addedGeorefMetadataLayer = true;
234
0
            else
235
0
                continue;
236
0
        }
237
238
0
        types.emplace_back(type);
239
0
    }
240
241
0
    return types;
242
0
}
243
244
//! Retrieve the BAG origin.
245
/*!
246
\return
247
    The geographic position of the south west corner of the BAG.
248
*/
249
const std::tuple<double, double>& Descriptor::getOrigin() const & noexcept
250
24
{
251
24
    return m_origin;
252
24
}
253
254
//! Retrieve the projected cover.
255
/*!
256
\return
257
    The projected cover of the BAG.
258
    The values returned in the tuple are:
259
    Lower left corner X, lower left corner Y, upper right corner X, upper right
260
    corner Y.
261
*/
262
const std::tuple<double, double, double, double>&
263
Descriptor::getProjectedCover() const & noexcept
264
24
{
265
24
    return m_projectedCover;
266
24
}
267
268
//! Retrieve the BAG version as a string.
269
/*!
270
\return
271
    The BAG version as a string.
272
*/
273
const std::string& Descriptor::getVersion() const & noexcept
274
266
{
275
266
    return m_version;
276
266
}
277
278
//! Retrieve the vertical reference system.
279
/*!
280
\return
281
    The vertical reference system.
282
*/
283
const std::string& Descriptor::getVerticalReferenceSystem() const & noexcept
284
24
{
285
24
    return m_verticalReferenceSystem;
286
24
}
287
288
//! Retrieve the read only flag value.
289
/*!
290
\return
291
    \e true if the BAG is read only.
292
    \e false otherwise.
293
*/
294
bool Descriptor::isReadOnly() const noexcept
295
0
{
296
0
    return m_isReadOnly;
297
0
}
298
299
//! Set the BAG grid size.
300
/*!
301
\param rows
302
    The number of rows in the BAG.
303
\param columns
304
    The number of columns in the BAG.
305
306
\return
307
    The modified descriptor.
308
*/
309
Descriptor& Descriptor::setDims(
310
    uint32_t rows,
311
    uint32_t columns) & noexcept
312
0
{
313
0
    m_dims = {rows, columns};
314
0
    return *this;
315
0
}
316
317
//! Set the BAG grid spacing/resolution.
318
/*!
319
\param xSpacing
320
    The X spacing/resolution of the BAG grid.
321
\param ySpacing
322
    The Y spacing/resolution of the BAG grid.
323
324
\return
325
    The modified descriptor.
326
*/
327
Descriptor& Descriptor::setGridSpacing(
328
    double xSpacing,
329
    double ySpacing) & noexcept
330
0
{
331
0
    m_gridSpacing = {xSpacing, ySpacing};
332
0
    return *this;
333
0
}
334
335
//! Set the BAG horizontal reference system.
336
/*!
337
\param horizontalReferenceSystem
338
    The new horizontal reference system as WKT.
339
340
\return
341
    The modified descriptor.
342
*/
343
Descriptor& Descriptor::setHorizontalReferenceSystem(
344
    const std::string& horizontalReferenceSystem) & noexcept
345
0
{
346
0
    m_horizontalReferenceSystem = horizontalReferenceSystem;
347
0
    return *this;
348
0
}
349
350
//! Set the BAG's origin.
351
/*!
352
\param llX
353
    Lower left x value.
354
\param llY
355
    Lower left y value.
356
357
\return
358
    The modified descriptor.
359
*/
360
Descriptor& Descriptor::setOrigin(
361
    double llX,
362
    double llY) & noexcept
363
0
{
364
0
    m_origin = {llX, llY};
365
0
    return *this;
366
0
}
367
368
//! Set the BAG's projected cover.
369
/*!
370
\param llX
371
    Lower left x value.
372
\param llY
373
    Lower left y value.
374
\param urX
375
    Upper right x value.
376
\param urY
377
    Upper right y value.
378
379
\return
380
    The modified descriptor.
381
*/
382
Descriptor& Descriptor::setProjectedCover(
383
    double llX,
384
    double llY,
385
    double urX,
386
    double urY) & noexcept
387
0
{
388
0
    m_projectedCover = {llX, llY, urX, urY};
389
0
    return *this;
390
0
}
391
392
//! Set the BAG's projected cover.
393
/*!
394
\param inReadOnly
395
    The new read only flag.
396
    \e true enables reading only.
397
    \e false allows writing.
398
399
\return
400
    The modified descriptor.
401
*/
402
Descriptor& Descriptor::setReadOnly(bool inReadOnly) & noexcept
403
242
{
404
242
    m_isReadOnly = inReadOnly;
405
242
    return *this;
406
242
}
407
408
//! Set the BAG's version as a string.
409
/*!
410
\param inVersion
411
    The new version as a string.
412
413
\return
414
    The modified descriptor.
415
*/
416
Descriptor& Descriptor::setVersion(std::string inVersion) & noexcept
417
242
{
418
242
    m_version = std::move(inVersion);
419
242
    return *this;
420
242
}
421
422
//! Set the BAG's vertical reference system.
423
/*!
424
\param verticalReferenceSystem
425
    The new vertical reference system as WKT.
426
427
\return
428
    The modified descriptor.
429
*/
430
Descriptor& Descriptor::setVerticalReferenceSystem(
431
    const std::string& verticalReferenceSystem) & noexcept
432
0
{
433
0
    m_verticalReferenceSystem = verticalReferenceSystem;
434
0
    return *this;
435
0
}
436
437
}  // namespace BAG
438