Coverage Report

Created: 2025-06-13 06:18

/src/proj/src/iso19111/operation/parametervalue.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  PROJ
4
 * Purpose:  ISO19111:2019 implementation
5
 * Author:   Even Rouault <even dot rouault at spatialys dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a
11
 * copy of this software and associated documentation files (the "Software"),
12
 * to deal in the Software without restriction, including without limitation
13
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14
 * and/or sell copies of the Software, and to permit persons to whom the
15
 * Software is furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included
18
 * in all copies or substantial portions of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
 * DEALINGS IN THE SOFTWARE.
27
 ****************************************************************************/
28
29
#ifndef FROM_PROJ_CPP
30
#define FROM_PROJ_CPP
31
#endif
32
33
#include "proj/common.hpp"
34
#include "proj/coordinateoperation.hpp"
35
#include "proj/util.hpp"
36
37
#include "proj/internal/internal.hpp"
38
39
#include <cassert>
40
#include <cstring>
41
#include <memory>
42
#include <string>
43
#include <vector>
44
45
using namespace NS_PROJ::internal;
46
47
// ---------------------------------------------------------------------------
48
49
NS_PROJ_START
50
namespace operation {
51
52
// ---------------------------------------------------------------------------
53
54
//! @cond Doxygen_Suppress
55
struct ParameterValue::Private {
56
    ParameterValue::Type type_{ParameterValue::Type::STRING};
57
    std::unique_ptr<common::Measure> measure_{};
58
    std::unique_ptr<std::string> stringValue_{};
59
    int integerValue_{};
60
    bool booleanValue_{};
61
62
    explicit Private(const common::Measure &valueIn)
63
0
        : type_(ParameterValue::Type::MEASURE),
64
0
          measure_(std::make_unique<common::Measure>(valueIn)) {}
65
66
    Private(const std::string &stringValueIn, ParameterValue::Type typeIn)
67
0
        : type_(typeIn),
68
0
          stringValue_(std::make_unique<std::string>(stringValueIn)) {}
69
70
    explicit Private(int integerValueIn)
71
0
        : type_(ParameterValue::Type::INTEGER), integerValue_(integerValueIn) {}
72
73
    explicit Private(bool booleanValueIn)
74
0
        : type_(ParameterValue::Type::BOOLEAN), booleanValue_(booleanValueIn) {}
75
};
76
//! @endcond
77
78
// ---------------------------------------------------------------------------
79
80
//! @cond Doxygen_Suppress
81
0
ParameterValue::~ParameterValue() = default;
82
//! @endcond
83
84
// ---------------------------------------------------------------------------
85
86
ParameterValue::ParameterValue(const common::Measure &measureIn)
87
0
    : d(std::make_unique<Private>(measureIn)) {}
88
89
// ---------------------------------------------------------------------------
90
91
ParameterValue::ParameterValue(const std::string &stringValueIn,
92
                               ParameterValue::Type typeIn)
93
0
    : d(std::make_unique<Private>(stringValueIn, typeIn)) {}
94
95
// ---------------------------------------------------------------------------
96
97
ParameterValue::ParameterValue(int integerValueIn)
98
0
    : d(std::make_unique<Private>(integerValueIn)) {}
99
100
// ---------------------------------------------------------------------------
101
102
ParameterValue::ParameterValue(bool booleanValueIn)
103
0
    : d(std::make_unique<Private>(booleanValueIn)) {}
104
105
// ---------------------------------------------------------------------------
106
107
/** \brief Instantiate a ParameterValue from a Measure (i.e. a value associated
108
 * with a
109
 * unit)
110
 *
111
 * @return a new ParameterValue.
112
 */
113
0
ParameterValueNNPtr ParameterValue::create(const common::Measure &measureIn) {
114
0
    return ParameterValue::nn_make_shared<ParameterValue>(measureIn);
115
0
}
116
117
// ---------------------------------------------------------------------------
118
119
/** \brief Instantiate a ParameterValue from a string value.
120
 *
121
 * @return a new ParameterValue.
122
 */
123
0
ParameterValueNNPtr ParameterValue::create(const char *stringValueIn) {
124
0
    return ParameterValue::nn_make_shared<ParameterValue>(
125
0
        std::string(stringValueIn), ParameterValue::Type::STRING);
126
0
}
127
128
// ---------------------------------------------------------------------------
129
130
/** \brief Instantiate a ParameterValue from a string value.
131
 *
132
 * @return a new ParameterValue.
133
 */
134
0
ParameterValueNNPtr ParameterValue::create(const std::string &stringValueIn) {
135
0
    return ParameterValue::nn_make_shared<ParameterValue>(
136
0
        stringValueIn, ParameterValue::Type::STRING);
137
0
}
138
139
// ---------------------------------------------------------------------------
140
141
/** \brief Instantiate a ParameterValue from a filename.
142
 *
143
 * @return a new ParameterValue.
144
 */
145
ParameterValueNNPtr
146
0
ParameterValue::createFilename(const std::string &stringValueIn) {
147
0
    return ParameterValue::nn_make_shared<ParameterValue>(
148
0
        stringValueIn, ParameterValue::Type::FILENAME);
149
0
}
150
151
// ---------------------------------------------------------------------------
152
153
/** \brief Instantiate a ParameterValue from a integer value.
154
 *
155
 * @return a new ParameterValue.
156
 */
157
0
ParameterValueNNPtr ParameterValue::create(int integerValueIn) {
158
0
    return ParameterValue::nn_make_shared<ParameterValue>(integerValueIn);
159
0
}
160
161
// ---------------------------------------------------------------------------
162
163
/** \brief Instantiate a ParameterValue from a boolean value.
164
 *
165
 * @return a new ParameterValue.
166
 */
167
0
ParameterValueNNPtr ParameterValue::create(bool booleanValueIn) {
168
0
    return ParameterValue::nn_make_shared<ParameterValue>(booleanValueIn);
169
0
}
170
171
// ---------------------------------------------------------------------------
172
173
/** \brief Returns the type of a parameter value.
174
 *
175
 * @return the type.
176
 */
177
0
const ParameterValue::Type &ParameterValue::type() PROJ_PURE_DEFN {
178
0
    return d->type_;
179
0
}
180
181
// ---------------------------------------------------------------------------
182
183
/** \brief Returns the value as a Measure (assumes type() == Type::MEASURE)
184
 * @return the value as a Measure.
185
 */
186
0
const common::Measure &ParameterValue::value() PROJ_PURE_DEFN {
187
0
    return *d->measure_;
188
0
}
189
190
// ---------------------------------------------------------------------------
191
192
/** \brief Returns the value as a string (assumes type() == Type::STRING)
193
 * @return the value as a string.
194
 */
195
0
const std::string &ParameterValue::stringValue() PROJ_PURE_DEFN {
196
0
    return *d->stringValue_;
197
0
}
198
199
// ---------------------------------------------------------------------------
200
201
/** \brief Returns the value as a filename (assumes type() == Type::FILENAME)
202
 * @return the value as a filename.
203
 */
204
0
const std::string &ParameterValue::valueFile() PROJ_PURE_DEFN {
205
0
    return *d->stringValue_;
206
0
}
207
208
// ---------------------------------------------------------------------------
209
210
/** \brief Returns the value as a integer (assumes type() == Type::INTEGER)
211
 * @return the value as a integer.
212
 */
213
0
int ParameterValue::integerValue() PROJ_PURE_DEFN { return d->integerValue_; }
214
215
// ---------------------------------------------------------------------------
216
217
/** \brief Returns the value as a boolean (assumes type() == Type::BOOLEAN)
218
 * @return the value as a boolean.
219
 */
220
0
bool ParameterValue::booleanValue() PROJ_PURE_DEFN { return d->booleanValue_; }
221
222
// ---------------------------------------------------------------------------
223
224
//! @cond Doxygen_Suppress
225
0
void ParameterValue::_exportToWKT(io::WKTFormatter *formatter) const {
226
0
    const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
227
228
0
    const auto &l_type = type();
229
0
    if (l_type == Type::MEASURE) {
230
0
        const auto &l_value = value();
231
0
        if (formatter->abridgedTransformation()) {
232
0
            const auto &unit = l_value.unit();
233
0
            const auto &unitType = unit.type();
234
0
            if (unitType == common::UnitOfMeasure::Type::LINEAR) {
235
0
                formatter->add(l_value.getSIValue());
236
0
            } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) {
237
0
                formatter->add(
238
0
                    l_value.convertToUnit(common::UnitOfMeasure::ARC_SECOND));
239
0
            } else if (unit == common::UnitOfMeasure::PARTS_PER_MILLION) {
240
0
                formatter->add(1.0 + l_value.value() * 1e-6);
241
0
            } else {
242
0
                formatter->add(l_value.value());
243
0
            }
244
0
        } else {
245
0
            const auto &unit = l_value.unit();
246
0
            if (isWKT2) {
247
0
                formatter->add(l_value.value());
248
0
            } else {
249
                // In WKT1, as we don't output the natural unit, output to the
250
                // registered linear / angular unit.
251
0
                const auto &unitType = unit.type();
252
0
                if (unitType == common::UnitOfMeasure::Type::LINEAR) {
253
0
                    const auto &targetUnit = *(formatter->axisLinearUnit());
254
0
                    if (targetUnit.conversionToSI() == 0.0) {
255
0
                        throw io::FormattingException(
256
0
                            "cannot convert value to target linear unit");
257
0
                    }
258
0
                    formatter->add(l_value.convertToUnit(targetUnit));
259
0
                } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) {
260
0
                    const auto &targetUnit = *(formatter->axisAngularUnit());
261
0
                    if (targetUnit.conversionToSI() == 0.0) {
262
0
                        throw io::FormattingException(
263
0
                            "cannot convert value to target angular unit");
264
0
                    }
265
0
                    formatter->add(l_value.convertToUnit(targetUnit));
266
0
                } else {
267
0
                    formatter->add(l_value.getSIValue());
268
0
                }
269
0
            }
270
0
            if (isWKT2 && unit != common::UnitOfMeasure::NONE) {
271
0
                if (!formatter
272
0
                         ->primeMeridianOrParameterUnitOmittedIfSameAsAxis() ||
273
0
                    (unit != common::UnitOfMeasure::SCALE_UNITY &&
274
0
                     unit != *(formatter->axisLinearUnit()) &&
275
0
                     unit != *(formatter->axisAngularUnit()))) {
276
0
                    unit._exportToWKT(formatter);
277
0
                }
278
0
            }
279
0
        }
280
0
    } else if (l_type == Type::STRING || l_type == Type::FILENAME) {
281
0
        formatter->addQuotedString(stringValue());
282
0
    } else if (l_type == Type::INTEGER) {
283
0
        formatter->add(integerValue());
284
0
    } else {
285
0
        throw io::FormattingException("boolean parameter value not handled");
286
0
    }
287
0
}
288
//! @endcond
289
290
// ---------------------------------------------------------------------------
291
292
//! @cond Doxygen_Suppress
293
bool ParameterValue::_isEquivalentTo(const util::IComparable *other,
294
                                     util::IComparable::Criterion criterion,
295
0
                                     const io::DatabaseContextPtr &) const {
296
0
    auto otherPV = dynamic_cast<const ParameterValue *>(other);
297
0
    if (otherPV == nullptr) {
298
0
        return false;
299
0
    }
300
0
    if (type() != otherPV->type()) {
301
0
        return false;
302
0
    }
303
0
    switch (type()) {
304
0
    case Type::MEASURE: {
305
0
        return value()._isEquivalentTo(otherPV->value(), criterion, 2e-10);
306
0
    }
307
308
0
    case Type::STRING:
309
0
    case Type::FILENAME: {
310
0
        return stringValue() == otherPV->stringValue();
311
0
    }
312
313
0
    case Type::INTEGER: {
314
0
        return integerValue() == otherPV->integerValue();
315
0
    }
316
317
0
    case Type::BOOLEAN: {
318
0
        return booleanValue() == otherPV->booleanValue();
319
0
    }
320
321
0
    default: {
322
0
        assert(false);
323
0
        break;
324
0
    }
325
0
    }
326
0
    return true;
327
0
}
328
//! @endcond
329
// ---------------------------------------------------------------------------
330
331
} // namespace operation
332
333
NS_PROJ_END