Coverage Report

Created: 2025-06-22 06:59

/src/proj/src/iso19111/coordinatesystem.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/coordinatesystem.hpp"
34
#include "proj/common.hpp"
35
#include "proj/io.hpp"
36
#include "proj/metadata.hpp"
37
#include "proj/util.hpp"
38
39
#include "proj/internal/coordinatesystem_internal.hpp"
40
#include "proj/internal/internal.hpp"
41
#include "proj/internal/io_internal.hpp"
42
43
#include "proj_json_streaming_writer.hpp"
44
45
#include <map>
46
#include <memory>
47
#include <set>
48
#include <string>
49
#include <vector>
50
51
using namespace NS_PROJ::internal;
52
53
#if 0
54
namespace dropbox{ namespace oxygen {
55
template<> nn<NS_PROJ::cs::MeridianPtr>::~nn() = default;
56
template<> nn<NS_PROJ::cs::CoordinateSystemAxisPtr>::~nn() = default;
57
template<> nn<NS_PROJ::cs::CoordinateSystemPtr>::~nn() = default;
58
template<> nn<NS_PROJ::cs::SphericalCSPtr>::~nn() = default;
59
template<> nn<NS_PROJ::cs::EllipsoidalCSPtr>::~nn() = default;
60
template<> nn<NS_PROJ::cs::CartesianCSPtr>::~nn() = default;
61
template<> nn<NS_PROJ::cs::TemporalCSPtr>::~nn() = default;
62
template<> nn<NS_PROJ::cs::TemporalCountCSPtr>::~nn() = default;
63
template<> nn<NS_PROJ::cs::TemporalMeasureCSPtr>::~nn() = default;
64
template<> nn<NS_PROJ::cs::DateTimeTemporalCSPtr>::~nn() = default;
65
template<> nn<NS_PROJ::cs::VerticalCSPtr>::~nn() = default;
66
template<> nn<NS_PROJ::cs::ParametricCSPtr>::~nn() = default;
67
template<> nn<NS_PROJ::cs::OrdinalCSPtr>::~nn() = default;
68
}}
69
#endif
70
71
NS_PROJ_START
72
namespace cs {
73
74
// ---------------------------------------------------------------------------
75
76
//! @cond Doxygen_Suppress
77
struct Meridian::Private {
78
    common::Angle longitude_{};
79
80
608
    explicit Private(const common::Angle &longitude) : longitude_(longitude) {}
81
};
82
//! @endcond
83
84
// ---------------------------------------------------------------------------
85
86
Meridian::Meridian(const common::Angle &longitudeIn)
87
608
    : d(std::make_unique<Private>(longitudeIn)) {}
88
89
// ---------------------------------------------------------------------------
90
91
#ifdef notdef
92
Meridian::Meridian(const Meridian &other)
93
    : IdentifiedObject(other), d(std::make_unique<Private>(*other.d)) {}
94
#endif
95
96
// ---------------------------------------------------------------------------
97
98
//! @cond Doxygen_Suppress
99
582
Meridian::~Meridian() = default;
100
//! @endcond
101
102
// ---------------------------------------------------------------------------
103
104
/** \brief Return the longitude of the meridian that the axis follows from the
105
 * pole.
106
 *
107
 * @return the longitude.
108
 */
109
0
const common::Angle &Meridian::longitude() PROJ_PURE_DEFN {
110
0
    return d->longitude_;
111
0
}
112
113
// ---------------------------------------------------------------------------
114
115
/** \brief Instantiate a Meridian.
116
 *
117
 * @param longitudeIn longitude of the meridian that the axis follows from the
118
 * pole.
119
 * @return new Meridian.
120
 */
121
608
MeridianNNPtr Meridian::create(const common::Angle &longitudeIn) {
122
608
    return Meridian::nn_make_shared<Meridian>(longitudeIn);
123
608
}
124
125
// ---------------------------------------------------------------------------
126
127
//! @cond Doxygen_Suppress
128
void Meridian::_exportToWKT(
129
    io::WKTFormatter *formatter) const // throw(FormattingException)
130
0
{
131
0
    formatter->startNode(io::WKTConstants::MERIDIAN, !identifiers().empty());
132
0
    formatter->add(longitude().value());
133
0
    longitude().unit()._exportToWKT(formatter, io::WKTConstants::ANGLEUNIT);
134
0
    if (formatter->outputId()) {
135
0
        formatID(formatter);
136
0
    }
137
0
    formatter->endNode();
138
0
}
139
//! @endcond
140
141
// ---------------------------------------------------------------------------
142
143
//! @cond Doxygen_Suppress
144
void Meridian::_exportToJSON(
145
    io::JSONFormatter *formatter) const // throw(FormattingException)
146
0
{
147
0
    auto writer = formatter->writer();
148
0
    auto objectContext(
149
0
        formatter->MakeObjectContext("Meridian", !identifiers().empty()));
150
151
0
    const auto &l_long = longitude();
152
0
    writer->AddObjKey("longitude");
153
0
    const auto &unit = l_long.unit();
154
0
    if (unit == common::UnitOfMeasure::DEGREE) {
155
0
        writer->Add(l_long.value(), 15);
156
0
    } else {
157
0
        auto longitudeContext(formatter->MakeObjectContext(nullptr, false));
158
0
        writer->AddObjKey("value");
159
0
        writer->Add(l_long.value(), 15);
160
0
        writer->AddObjKey("unit");
161
0
        unit._exportToJSON(formatter);
162
0
    }
163
0
    if (formatter->outputId()) {
164
0
        formatID(formatter);
165
0
    }
166
0
}
167
//! @endcond
168
169
// ---------------------------------------------------------------------------
170
171
//! @cond Doxygen_Suppress
172
struct CoordinateSystemAxis::Private {
173
    std::string abbreviation{};
174
    const AxisDirection *direction = &(AxisDirection::UNSPECIFIED);
175
    common::UnitOfMeasure unit{};
176
    util::optional<RangeMeaning> rangeMeaning = util::optional<RangeMeaning>();
177
    util::optional<double> minimumValue{};
178
    util::optional<double> maximumValue{};
179
    MeridianPtr meridian{};
180
};
181
//! @endcond
182
183
// ---------------------------------------------------------------------------
184
185
442k
CoordinateSystemAxis::CoordinateSystemAxis() : d(std::make_unique<Private>()) {}
186
187
// ---------------------------------------------------------------------------
188
189
#ifdef notdef
190
CoordinateSystemAxis::CoordinateSystemAxis(const CoordinateSystemAxis &other)
191
    : IdentifiedObject(other), d(std::make_unique<Private>(*other.d)) {}
192
#endif
193
194
// ---------------------------------------------------------------------------
195
196
//! @cond Doxygen_Suppress
197
442k
CoordinateSystemAxis::~CoordinateSystemAxis() = default;
198
//! @endcond
199
200
// ---------------------------------------------------------------------------
201
202
/** \brief Return the axis abbreviation.
203
 *
204
 * The abbreviation used for this coordinate system axis; this abbreviation
205
 * is also used to identify the coordinates in the coordinate tuple.
206
 * Examples are X and Y.
207
 *
208
 * @return the abbreviation.
209
 */
210
564
const std::string &CoordinateSystemAxis::abbreviation() PROJ_PURE_DEFN {
211
564
    return d->abbreviation;
212
564
}
213
214
// ---------------------------------------------------------------------------
215
216
/** \brief Return the axis direction.
217
 *
218
 * The direction of this coordinate system axis (or in the case of Cartesian
219
 * projected coordinates, the direction of this coordinate system axis locally)
220
 * Examples: north or south, east or west, up or down. Within any set of
221
 * coordinate system axes, only one of each pair of terms can be used. For
222
 * Earth-fixed CRSs, this direction is often approximate and intended to
223
 * provide a human interpretable meaning to the axis. When a geodetic reference
224
 * frame is used, the precise directions of the axes may therefore vary
225
 * slightly from this approximate direction. Note that an EngineeringCRS often
226
 * requires specific descriptions of the directions of its coordinate system
227
 * axes.
228
 *
229
 * @return the direction.
230
 */
231
3.99k
const AxisDirection &CoordinateSystemAxis::direction() PROJ_PURE_DEFN {
232
3.99k
    return *(d->direction);
233
3.99k
}
234
235
// ---------------------------------------------------------------------------
236
237
/** \brief Return the axis unit.
238
 *
239
 * This is the spatial unit or temporal quantity used for this coordinate
240
 * system axis. The value of a coordinate in a coordinate tuple shall be
241
 * recorded using this unit.
242
 *
243
 * @return the axis unit.
244
 */
245
11.6k
const common::UnitOfMeasure &CoordinateSystemAxis::unit() PROJ_PURE_DEFN {
246
11.6k
    return d->unit;
247
11.6k
}
248
249
// ---------------------------------------------------------------------------
250
251
/** \brief Return the minimum value normally allowed for this axis, in the unit
252
 * for the axis.
253
 *
254
 * @return the minimum value, or empty.
255
 */
256
const util::optional<double> &
257
0
CoordinateSystemAxis::minimumValue() PROJ_PURE_DEFN {
258
0
    return d->minimumValue;
259
0
}
260
261
// ---------------------------------------------------------------------------
262
263
/** \brief Return the maximum value normally allowed for this axis, in the unit
264
 * for the axis.
265
 *
266
 * @return the maximum value, or empty.
267
 */
268
const util::optional<double> &
269
0
CoordinateSystemAxis::maximumValue() PROJ_PURE_DEFN {
270
0
    return d->maximumValue;
271
0
}
272
273
// ---------------------------------------------------------------------------
274
275
/** \brief Return the range meaning
276
 *
277
 * @return the range meaning, or empty.
278
 * @since 9.2
279
 */
280
const util::optional<RangeMeaning> &
281
0
CoordinateSystemAxis::rangeMeaning() PROJ_PURE_DEFN {
282
0
    return d->rangeMeaning;
283
0
}
284
285
// ---------------------------------------------------------------------------
286
287
/** \brief Return the meridian that the axis follows from the pole, for a
288
 * coordinate
289
 * reference system centered on a pole.
290
 *
291
 * @return the meridian, or null.
292
 */
293
0
const MeridianPtr &CoordinateSystemAxis::meridian() PROJ_PURE_DEFN {
294
0
    return d->meridian;
295
0
}
296
297
// ---------------------------------------------------------------------------
298
299
/** \brief Instantiate a CoordinateSystemAxis.
300
 *
301
 * @param properties See \ref general_properties. The name should generally be
302
 * defined.
303
 * @param abbreviationIn Axis abbreviation (might be empty)
304
 * @param directionIn Axis direction
305
 * @param unitIn Axis unit
306
 * @param meridianIn The meridian that the axis follows from the pole, for a
307
 * coordinate
308
 * reference system centered on a pole, or nullptr
309
 * @return a new CoordinateSystemAxis.
310
 */
311
CoordinateSystemAxisNNPtr CoordinateSystemAxis::create(
312
    const util::PropertyMap &properties, const std::string &abbreviationIn,
313
    const AxisDirection &directionIn, const common::UnitOfMeasure &unitIn,
314
442k
    const MeridianPtr &meridianIn) {
315
442k
    auto csa(CoordinateSystemAxis::nn_make_shared<CoordinateSystemAxis>());
316
442k
    csa->setProperties(properties);
317
442k
    csa->d->abbreviation = abbreviationIn;
318
442k
    csa->d->direction = &directionIn;
319
442k
    csa->d->unit = unitIn;
320
442k
    csa->d->meridian = meridianIn;
321
442k
    return csa;
322
442k
}
323
324
// ---------------------------------------------------------------------------
325
326
/** \brief Instantiate a CoordinateSystemAxis.
327
 *
328
 * @param properties See \ref general_properties. The name should generally be
329
 * defined.
330
 * @param abbreviationIn Axis abbreviation (might be empty)
331
 * @param directionIn Axis direction
332
 * @param unitIn Axis unit
333
 * @param minimumValueIn Minimum value along axis
334
 * @param maximumValueIn Maximum value along axis
335
 * @param rangeMeaningIn Range Meaning
336
 * @param meridianIn The meridian that the axis follows from the pole, for a
337
 * coordinate
338
 * reference system centered on a pole, or nullptr
339
 * @return a new CoordinateSystemAxis.
340
 * @since 9.2
341
 */
342
CoordinateSystemAxisNNPtr CoordinateSystemAxis::create(
343
    const util::PropertyMap &properties, const std::string &abbreviationIn,
344
    const AxisDirection &directionIn, const common::UnitOfMeasure &unitIn,
345
    const util::optional<double> &minimumValueIn,
346
    const util::optional<double> &maximumValueIn,
347
    const util::optional<RangeMeaning> &rangeMeaningIn,
348
416
    const MeridianPtr &meridianIn) {
349
416
    auto csa(CoordinateSystemAxis::nn_make_shared<CoordinateSystemAxis>());
350
416
    csa->setProperties(properties);
351
416
    csa->d->abbreviation = abbreviationIn;
352
416
    csa->d->direction = &directionIn;
353
416
    csa->d->unit = unitIn;
354
416
    csa->d->minimumValue = minimumValueIn;
355
416
    csa->d->maximumValue = maximumValueIn;
356
416
    csa->d->rangeMeaning = rangeMeaningIn;
357
416
    csa->d->meridian = meridianIn;
358
416
    return csa;
359
416
}
360
361
// ---------------------------------------------------------------------------
362
363
//! @cond Doxygen_Suppress
364
void CoordinateSystemAxis::_exportToWKT(
365
    // cppcheck-suppress passedByValue
366
    io::WKTFormatter *formatter) const // throw(FormattingException)
367
0
{
368
0
    _exportToWKT(formatter, 0, false);
369
0
}
370
//! @endcond
371
372
// ---------------------------------------------------------------------------
373
374
//! @cond Doxygen_Suppress
375
503
std::string CoordinateSystemAxis::normalizeAxisName(const std::string &str) {
376
503
    if (str.empty()) {
377
5
        return str;
378
5
    }
379
    // on import, transform from WKT2 "longitude" to "Longitude", as in the
380
    // EPSG database.
381
498
    return toupper(str.substr(0, 1)) + str.substr(1);
382
503
}
383
//! @endcond
384
385
// ---------------------------------------------------------------------------
386
387
//! @cond Doxygen_Suppress
388
void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order,
389
0
                                        bool disableAbbrev) const {
390
0
    const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
391
0
    formatter->startNode(io::WKTConstants::AXIS, !identifiers().empty());
392
0
    const std::string &axisName = nameStr();
393
0
    const std::string &abbrev = abbreviation();
394
0
    std::string parenthesizedAbbrev =
395
0
        std::string("(").append(abbrev).append(")");
396
0
    std::string dir = direction().toString();
397
0
    std::string axisDesignation;
398
399
    // It seems that the convention in WKT2 for axis name is first letter in
400
    // lower case. Whereas in WKT1 GDAL, it is in upper case (as in the EPSG
401
    // database)
402
0
    if (!axisName.empty()) {
403
0
        if (isWKT2) {
404
0
            axisDesignation =
405
0
                tolower(axisName.substr(0, 1)) + axisName.substr(1);
406
0
        } else {
407
0
            if (axisName == "Geodetic latitude") {
408
0
                axisDesignation = "Latitude";
409
0
            } else if (axisName == "Geodetic longitude") {
410
0
                axisDesignation = "Longitude";
411
0
            } else {
412
0
                axisDesignation = axisName;
413
0
            }
414
0
        }
415
0
    }
416
417
0
    if (!disableAbbrev && isWKT2 &&
418
        // For geodetic CS, export the axis name without abbreviation
419
0
        !(axisName == AxisName::Latitude || axisName == AxisName::Longitude)) {
420
0
        if (!axisDesignation.empty() && !abbrev.empty()) {
421
0
            axisDesignation += " ";
422
0
        }
423
0
        if (!abbrev.empty()) {
424
0
            axisDesignation += parenthesizedAbbrev;
425
0
        }
426
0
    }
427
0
    if (!isWKT2) {
428
0
        dir = toupper(dir);
429
430
0
        if (direction() == AxisDirection::GEOCENTRIC_Z) {
431
0
            dir = AxisDirectionWKT1::NORTH;
432
0
        } else if (AxisDirectionWKT1::valueOf(dir) == nullptr) {
433
0
            dir = AxisDirectionWKT1::OTHER;
434
0
        }
435
0
    } else if (!abbrev.empty()) {
436
        // For geocentric CS, just put the abbreviation
437
0
        if (direction() == AxisDirection::GEOCENTRIC_X ||
438
0
            direction() == AxisDirection::GEOCENTRIC_Y ||
439
0
            direction() == AxisDirection::GEOCENTRIC_Z) {
440
0
            axisDesignation = std::move(parenthesizedAbbrev);
441
0
        }
442
        // For cartesian CS with Easting/Northing, export only the abbreviation
443
0
        else if ((order == 1 && axisName == AxisName::Easting &&
444
0
                  abbrev == AxisAbbreviation::E) ||
445
0
                 (order == 2 && axisName == AxisName::Northing &&
446
0
                  abbrev == AxisAbbreviation::N)) {
447
0
            axisDesignation = std::move(parenthesizedAbbrev);
448
0
        }
449
0
    }
450
0
    formatter->addQuotedString(axisDesignation);
451
0
    formatter->add(dir);
452
0
    const auto &l_meridian = meridian();
453
0
    if (isWKT2 && l_meridian) {
454
0
        l_meridian->_exportToWKT(formatter);
455
0
    }
456
0
    if (formatter->outputAxisOrder() && order > 0) {
457
0
        formatter->startNode(io::WKTConstants::ORDER, false);
458
0
        formatter->add(order);
459
0
        formatter->endNode();
460
0
    }
461
0
    if (formatter->outputUnit() &&
462
0
        unit().type() != common::UnitOfMeasure::Type::NONE) {
463
0
        unit()._exportToWKT(formatter);
464
0
    }
465
0
    if (isWKT2 && formatter->use2019Keywords()) {
466
0
        if (d->minimumValue.has_value()) {
467
0
            formatter->startNode(io::WKTConstants::AXISMINVALUE, false);
468
0
            formatter->add(*(d->minimumValue));
469
0
            formatter->endNode();
470
0
        }
471
0
        if (d->maximumValue.has_value()) {
472
0
            formatter->startNode(io::WKTConstants::AXISMAXVALUE, false);
473
0
            formatter->add(*(d->maximumValue));
474
0
            formatter->endNode();
475
0
        }
476
0
        if (d->minimumValue.has_value() && d->maximumValue.has_value() &&
477
0
            d->rangeMeaning.has_value()) {
478
0
            formatter->startNode(io::WKTConstants::RANGEMEANING, false);
479
0
            formatter->add(d->rangeMeaning->toString());
480
0
            formatter->endNode();
481
0
        }
482
0
    }
483
0
    if (formatter->outputId()) {
484
0
        formatID(formatter);
485
0
    }
486
0
    formatter->endNode();
487
0
}
488
//! @endcond
489
490
// ---------------------------------------------------------------------------
491
492
//! @cond Doxygen_Suppress
493
void CoordinateSystemAxis::_exportToJSON(
494
    io::JSONFormatter *formatter) const // throw(FormattingException)
495
0
{
496
0
    auto writer = formatter->writer();
497
0
    auto objectContext(
498
0
        formatter->MakeObjectContext("Axis", !identifiers().empty()));
499
500
0
    writer->AddObjKey("name");
501
0
    writer->Add(nameStr());
502
503
0
    writer->AddObjKey("abbreviation");
504
0
    writer->Add(abbreviation());
505
506
0
    writer->AddObjKey("direction");
507
0
    writer->Add(direction().toString());
508
509
0
    const auto &l_meridian = meridian();
510
0
    if (l_meridian) {
511
0
        writer->AddObjKey("meridian");
512
0
        formatter->setOmitTypeInImmediateChild();
513
0
        l_meridian->_exportToJSON(formatter);
514
0
    }
515
516
0
    const auto &l_unit(unit());
517
0
    if (l_unit == common::UnitOfMeasure::METRE ||
518
0
        l_unit == common::UnitOfMeasure::DEGREE) {
519
0
        writer->AddObjKey("unit");
520
0
        writer->Add(l_unit.name());
521
0
    } else if (l_unit.type() != common::UnitOfMeasure::Type::NONE) {
522
0
        writer->AddObjKey("unit");
523
0
        l_unit._exportToJSON(formatter);
524
0
    }
525
526
0
    if (d->minimumValue.has_value()) {
527
0
        writer->AddObjKey("minimum_value");
528
0
        writer->Add(*(d->minimumValue));
529
0
    }
530
531
0
    if (d->maximumValue.has_value()) {
532
0
        writer->AddObjKey("maximum_value");
533
0
        writer->Add(*(d->maximumValue));
534
0
    }
535
536
0
    if (d->minimumValue.has_value() && d->maximumValue.has_value() &&
537
0
        d->rangeMeaning.has_value()) {
538
0
        writer->AddObjKey("range_meaning");
539
0
        writer->Add(d->rangeMeaning->toString());
540
0
    }
541
542
0
    if (formatter->outputId()) {
543
0
        formatID(formatter);
544
0
    }
545
0
}
546
//! @endcond
547
548
// ---------------------------------------------------------------------------
549
550
//! @cond Doxygen_Suppress
551
bool CoordinateSystemAxis::_isEquivalentTo(
552
    const util::IComparable *other, util::IComparable::Criterion criterion,
553
282
    const io::DatabaseContextPtr &dbContext) const {
554
282
    auto otherCSA = dynamic_cast<const CoordinateSystemAxis *>(other);
555
282
    if (otherCSA == nullptr) {
556
0
        return false;
557
0
    }
558
    // For approximate comparison, only care about axis direction and unit.
559
282
    if (!(*(d->direction) == *(otherCSA->d->direction) &&
560
282
          d->unit._isEquivalentTo(otherCSA->d->unit, criterion))) {
561
0
        return false;
562
0
    }
563
282
    if (criterion == util::IComparable::Criterion::STRICT) {
564
282
        if (!IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) {
565
0
            return false;
566
0
        }
567
282
        if (abbreviation() != otherCSA->abbreviation()) {
568
0
            return false;
569
0
        }
570
        // TODO other metadata
571
282
    }
572
573
282
    return true;
574
282
}
575
//! @endcond
576
577
// ---------------------------------------------------------------------------
578
579
//! @cond Doxygen_Suppress
580
CoordinateSystemAxisNNPtr
581
0
CoordinateSystemAxis::alterUnit(const common::UnitOfMeasure &newUnit) const {
582
0
    return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY, name()),
583
0
                  abbreviation(), direction(), newUnit, meridian());
584
0
}
585
//! @endcond
586
587
// ---------------------------------------------------------------------------
588
589
//! @cond Doxygen_Suppress
590
struct CoordinateSystem::Private {
591
    std::vector<CoordinateSystemAxisNNPtr> axisList{};
592
593
    explicit Private(const std::vector<CoordinateSystemAxisNNPtr> &axisListIn)
594
110k
        : axisList(axisListIn) {}
595
};
596
//! @endcond
597
598
// ---------------------------------------------------------------------------
599
600
CoordinateSystem::CoordinateSystem(
601
    const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
602
110k
    : d(std::make_unique<Private>(axisIn)) {}
603
604
// ---------------------------------------------------------------------------
605
606
#ifdef notdef
607
CoordinateSystem::CoordinateSystem(const CoordinateSystem &other)
608
    : IdentifiedObject(other), d(std::make_unique<Private>(*other.d)) {}
609
#endif
610
611
// ---------------------------------------------------------------------------
612
613
//! @cond Doxygen_Suppress
614
110k
CoordinateSystem::~CoordinateSystem() = default;
615
//! @endcond
616
617
// ---------------------------------------------------------------------------
618
619
/** \brief Return the list of axes of this coordinate system.
620
 *
621
 * @return the axes.
622
 */
623
const std::vector<CoordinateSystemAxisNNPtr> &
624
60.8k
CoordinateSystem::axisList() PROJ_PURE_DEFN {
625
60.8k
    return d->axisList;
626
60.8k
}
627
628
// ---------------------------------------------------------------------------
629
630
//! @cond Doxygen_Suppress
631
void CoordinateSystem::_exportToWKT(
632
    io::WKTFormatter *formatter) const // throw(FormattingException)
633
0
{
634
0
    if (formatter->outputAxis() != io::WKTFormatter::OutputAxisRule::YES) {
635
0
        return;
636
0
    }
637
0
    const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
638
639
0
    const auto &l_axisList = axisList();
640
0
    if (isWKT2) {
641
0
        formatter->startNode(io::WKTConstants::CS_, !identifiers().empty());
642
0
        formatter->add(getWKT2Type(formatter->use2019Keywords()));
643
0
        formatter->add(static_cast<int>(l_axisList.size()));
644
0
        formatter->endNode();
645
0
        formatter->startNode(std::string(),
646
0
                             false); // anonymous indentation level
647
0
    }
648
649
0
    common::UnitOfMeasure unit = common::UnitOfMeasure::NONE;
650
0
    bool bAllSameUnit = true;
651
0
    bool bFirstUnit = true;
652
0
    for (const auto &axis : l_axisList) {
653
0
        const auto &l_unit = axis->unit();
654
0
        if (bFirstUnit) {
655
0
            unit = l_unit;
656
0
            bFirstUnit = false;
657
0
        } else if (unit != l_unit) {
658
0
            bAllSameUnit = false;
659
0
        }
660
0
    }
661
662
0
    formatter->pushOutputUnit(
663
0
        isWKT2 && (!bAllSameUnit || !formatter->outputCSUnitOnlyOnceIfSame()));
664
665
0
    int order = 1;
666
0
    const bool disableAbbrev =
667
0
        (l_axisList.size() == 3 &&
668
0
         l_axisList[0]->nameStr() == AxisName::Latitude &&
669
0
         l_axisList[1]->nameStr() == AxisName::Longitude &&
670
0
         l_axisList[2]->nameStr() == AxisName::Ellipsoidal_height);
671
672
0
    for (auto &axis : l_axisList) {
673
0
        int axisOrder = (isWKT2 && l_axisList.size() > 1) ? order : 0;
674
0
        axis->_exportToWKT(formatter, axisOrder, disableAbbrev);
675
0
        order++;
676
0
    }
677
0
    if (isWKT2 && !l_axisList.empty() && bAllSameUnit &&
678
0
        formatter->outputCSUnitOnlyOnceIfSame()) {
679
0
        unit._exportToWKT(formatter);
680
0
    }
681
682
0
    formatter->popOutputUnit();
683
684
0
    if (isWKT2) {
685
0
        formatter->endNode();
686
0
    }
687
0
}
688
//! @endcond
689
690
// ---------------------------------------------------------------------------
691
692
//! @cond Doxygen_Suppress
693
void CoordinateSystem::_exportToJSON(
694
    io::JSONFormatter *formatter) const // throw(FormattingException)
695
0
{
696
0
    auto writer = formatter->writer();
697
0
    auto objectContext(formatter->MakeObjectContext("CoordinateSystem",
698
0
                                                    !identifiers().empty()));
699
700
0
    writer->AddObjKey("subtype");
701
0
    writer->Add(getWKT2Type(true));
702
703
0
    writer->AddObjKey("axis");
704
0
    {
705
0
        auto axisContext(writer->MakeArrayContext(false));
706
0
        const auto &l_axisList = axisList();
707
0
        for (auto &axis : l_axisList) {
708
0
            formatter->setOmitTypeInImmediateChild();
709
0
            axis->_exportToJSON(formatter);
710
0
        }
711
0
    }
712
713
0
    if (formatter->outputId()) {
714
0
        formatID(formatter);
715
0
    }
716
0
}
717
718
//! @endcond
719
720
// ---------------------------------------------------------------------------
721
722
//! @cond Doxygen_Suppress
723
bool CoordinateSystem::_isEquivalentTo(
724
    const util::IComparable *other, util::IComparable::Criterion criterion,
725
144
    const io::DatabaseContextPtr &dbContext) const {
726
144
    auto otherCS = dynamic_cast<const CoordinateSystem *>(other);
727
144
    if (otherCS == nullptr ||
728
144
        !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) {
729
0
        return false;
730
0
    }
731
144
    const auto &list = axisList();
732
144
    const auto &otherList = otherCS->axisList();
733
144
    if (list.size() != otherList.size()) {
734
3
        return false;
735
3
    }
736
141
    if (getWKT2Type(true) != otherCS->getWKT2Type(true)) {
737
0
        return false;
738
0
    }
739
423
    for (size_t i = 0; i < list.size(); i++) {
740
282
        if (!list[i]->_isEquivalentTo(otherList[i].get(), criterion,
741
282
                                      dbContext)) {
742
0
            return false;
743
0
        }
744
282
    }
745
141
    return true;
746
141
}
747
//! @endcond
748
749
// ---------------------------------------------------------------------------
750
751
//! @cond Doxygen_Suppress
752
SphericalCS::~SphericalCS() = default;
753
//! @endcond
754
755
// ---------------------------------------------------------------------------
756
757
SphericalCS::SphericalCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
758
1.51k
    : CoordinateSystem(axisIn) {}
759
760
// ---------------------------------------------------------------------------
761
762
#ifdef notdef
763
SphericalCS::SphericalCS(const SphericalCS &) = default;
764
#endif
765
766
// ---------------------------------------------------------------------------
767
768
/** \brief Instantiate a SphericalCS.
769
 *
770
 * @param properties See \ref general_properties.
771
 * @param axis1 The first axis.
772
 * @param axis2 The second axis.
773
 * @param axis3 The third axis.
774
 * @return a new SphericalCS.
775
 */
776
SphericalCSNNPtr SphericalCS::create(const util::PropertyMap &properties,
777
                                     const CoordinateSystemAxisNNPtr &axis1,
778
                                     const CoordinateSystemAxisNNPtr &axis2,
779
0
                                     const CoordinateSystemAxisNNPtr &axis3) {
780
0
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
781
0
    auto cs(SphericalCS::nn_make_shared<SphericalCS>(axis));
782
0
    cs->setProperties(properties);
783
0
    return cs;
784
0
}
785
786
// ---------------------------------------------------------------------------
787
788
/** \brief Instantiate a SphericalCS with 2 axis.
789
 *
790
 * This is an extension to ISO19111 to support (planet)-ocentric CS with
791
 * geocentric latitude.
792
 *
793
 * @param properties See \ref general_properties.
794
 * @param axis1 The first axis.
795
 * @param axis2 The second axis.
796
 * @return a new SphericalCS.
797
 */
798
SphericalCSNNPtr SphericalCS::create(const util::PropertyMap &properties,
799
                                     const CoordinateSystemAxisNNPtr &axis1,
800
1.51k
                                     const CoordinateSystemAxisNNPtr &axis2) {
801
1.51k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
802
1.51k
    auto cs(SphericalCS::nn_make_shared<SphericalCS>(axis));
803
1.51k
    cs->setProperties(properties);
804
1.51k
    return cs;
805
1.51k
}
806
807
// ---------------------------------------------------------------------------
808
809
//! @cond Doxygen_Suppress
810
EllipsoidalCS::~EllipsoidalCS() = default;
811
//! @endcond
812
813
// ---------------------------------------------------------------------------
814
815
EllipsoidalCS::EllipsoidalCS(
816
    const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
817
60.0k
    : CoordinateSystem(axisIn) {}
818
819
// ---------------------------------------------------------------------------
820
821
#ifdef notdef
822
EllipsoidalCS::EllipsoidalCS(const EllipsoidalCS &) = default;
823
#endif
824
825
// ---------------------------------------------------------------------------
826
827
/** \brief Instantiate a EllipsoidalCS.
828
 *
829
 * @param properties See \ref general_properties.
830
 * @param axis1 The first axis.
831
 * @param axis2 The second axis.
832
 * @return a new EllipsoidalCS.
833
 */
834
EllipsoidalCSNNPtr
835
EllipsoidalCS::create(const util::PropertyMap &properties,
836
                      const CoordinateSystemAxisNNPtr &axis1,
837
58.2k
                      const CoordinateSystemAxisNNPtr &axis2) {
838
58.2k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
839
58.2k
    auto cs(EllipsoidalCS::nn_make_shared<EllipsoidalCS>(axis));
840
58.2k
    cs->setProperties(properties);
841
58.2k
    return cs;
842
58.2k
}
843
844
// ---------------------------------------------------------------------------
845
846
/** \brief Instantiate a EllipsoidalCS.
847
 *
848
 * @param properties See \ref general_properties.
849
 * @param axis1 The first axis.
850
 * @param axis2 The second axis.
851
 * @param axis3 The third axis.
852
 * @return a new EllipsoidalCS.
853
 */
854
EllipsoidalCSNNPtr
855
EllipsoidalCS::create(const util::PropertyMap &properties,
856
                      const CoordinateSystemAxisNNPtr &axis1,
857
                      const CoordinateSystemAxisNNPtr &axis2,
858
1.80k
                      const CoordinateSystemAxisNNPtr &axis3) {
859
1.80k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
860
1.80k
    auto cs(EllipsoidalCS::nn_make_shared<EllipsoidalCS>(axis));
861
1.80k
    cs->setProperties(properties);
862
1.80k
    return cs;
863
1.80k
}
864
865
// ---------------------------------------------------------------------------
866
867
//! @cond Doxygen_Suppress
868
CoordinateSystemAxisNNPtr
869
4.06k
CoordinateSystemAxis::createLAT_NORTH(const common::UnitOfMeasure &unit) {
870
4.06k
    return create(
871
4.06k
        util::PropertyMap().set(IdentifiedObject::NAME_KEY, AxisName::Latitude),
872
4.06k
        AxisAbbreviation::lat, AxisDirection::NORTH, unit);
873
4.06k
}
874
875
CoordinateSystemAxisNNPtr
876
4.06k
CoordinateSystemAxis::createLONG_EAST(const common::UnitOfMeasure &unit) {
877
4.06k
    return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY,
878
4.06k
                                          AxisName::Longitude),
879
4.06k
                  AxisAbbreviation::lon, AxisDirection::EAST, unit);
880
4.06k
}
881
//! @endcond
882
883
// ---------------------------------------------------------------------------
884
885
/** \brief Instantiate a EllipsoidalCS with a Latitude (first) and Longitude
886
 * (second) axis.
887
 *
888
 * @param unit Angular unit of the axes.
889
 * @return a new EllipsoidalCS.
890
 */
891
EllipsoidalCSNNPtr
892
758
EllipsoidalCS::createLatitudeLongitude(const common::UnitOfMeasure &unit) {
893
758
    return EllipsoidalCS::create(util::PropertyMap(),
894
758
                                 CoordinateSystemAxis::createLAT_NORTH(unit),
895
758
                                 CoordinateSystemAxis::createLONG_EAST(unit));
896
758
}
897
898
// ---------------------------------------------------------------------------
899
900
/** \brief Instantiate a EllipsoidalCS with a Latitude (first), Longitude
901
 * (second) axis and ellipsoidal height (third) axis.
902
 *
903
 * @param angularUnit Angular unit of the latitude and longitude axes.
904
 * @param linearUnit Linear unit of the ellipsoidal height axis.
905
 * @return a new EllipsoidalCS.
906
 */
907
EllipsoidalCSNNPtr EllipsoidalCS::createLatitudeLongitudeEllipsoidalHeight(
908
    const common::UnitOfMeasure &angularUnit,
909
6
    const common::UnitOfMeasure &linearUnit) {
910
6
    return EllipsoidalCS::create(
911
6
        util::PropertyMap(), CoordinateSystemAxis::createLAT_NORTH(angularUnit),
912
6
        CoordinateSystemAxis::createLONG_EAST(angularUnit),
913
6
        CoordinateSystemAxis::create(
914
6
            util::PropertyMap().set(IdentifiedObject::NAME_KEY,
915
6
                                    AxisName::Ellipsoidal_height),
916
6
            AxisAbbreviation::h, AxisDirection::UP, linearUnit));
917
6
}
918
919
// ---------------------------------------------------------------------------
920
921
/** \brief Instantiate a EllipsoidalCS with a Longitude (first) and Latitude
922
 * (second) axis.
923
 *
924
 * @param unit Angular unit of the axes.
925
 * @return a new EllipsoidalCS.
926
 */
927
EllipsoidalCSNNPtr
928
3.23k
EllipsoidalCS::createLongitudeLatitude(const common::UnitOfMeasure &unit) {
929
3.23k
    return EllipsoidalCS::create(util::PropertyMap(),
930
3.23k
                                 CoordinateSystemAxis::createLONG_EAST(unit),
931
3.23k
                                 CoordinateSystemAxis::createLAT_NORTH(unit));
932
3.23k
}
933
934
// ---------------------------------------------------------------------------
935
936
/** \brief Instantiate a EllipsoidalCS with a Longitude (first), Latitude
937
 * (second) axis and ellipsoidal height (third) axis.
938
 *
939
 * @param angularUnit Angular unit of the latitude and longitude axes.
940
 * @param linearUnit Linear unit of the ellipsoidal height axis.
941
 * @return a new EllipsoidalCS.
942
 * @since 7.0
943
 */
944
EllipsoidalCSNNPtr EllipsoidalCS::createLongitudeLatitudeEllipsoidalHeight(
945
    const common::UnitOfMeasure &angularUnit,
946
62
    const common::UnitOfMeasure &linearUnit) {
947
62
    return EllipsoidalCS::create(
948
62
        util::PropertyMap(), CoordinateSystemAxis::createLONG_EAST(angularUnit),
949
62
        CoordinateSystemAxis::createLAT_NORTH(angularUnit),
950
62
        CoordinateSystemAxis::create(
951
62
            util::PropertyMap().set(IdentifiedObject::NAME_KEY,
952
62
                                    AxisName::Ellipsoidal_height),
953
62
            AxisAbbreviation::h, AxisDirection::UP, linearUnit));
954
62
}
955
956
// ---------------------------------------------------------------------------
957
958
//! @cond Doxygen_Suppress
959
/** \brief Return the axis order in an enumerated way. */
960
0
EllipsoidalCS::AxisOrder EllipsoidalCS::axisOrder() const {
961
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
962
0
    const auto &dir0 = l_axisList[0]->direction();
963
0
    const auto &dir1 = l_axisList[1]->direction();
964
0
    if (&dir0 == &AxisDirection::NORTH && &dir1 == &AxisDirection::EAST) {
965
0
        if (l_axisList.size() == 2) {
966
0
            return AxisOrder::LAT_NORTH_LONG_EAST;
967
0
        } else if (&l_axisList[2]->direction() == &AxisDirection::UP) {
968
0
            return AxisOrder::LAT_NORTH_LONG_EAST_HEIGHT_UP;
969
0
        }
970
0
    } else if (&dir0 == &AxisDirection::EAST &&
971
0
               &dir1 == &AxisDirection::NORTH) {
972
0
        if (l_axisList.size() == 2) {
973
0
            return AxisOrder::LONG_EAST_LAT_NORTH;
974
0
        } else if (&l_axisList[2]->direction() == &AxisDirection::UP) {
975
0
            return AxisOrder::LONG_EAST_LAT_NORTH_HEIGHT_UP;
976
0
        }
977
0
    }
978
979
0
    return AxisOrder::OTHER;
980
0
}
981
//! @endcond
982
983
// ---------------------------------------------------------------------------
984
985
//! @cond Doxygen_Suppress
986
EllipsoidalCSNNPtr EllipsoidalCS::alterAngularUnit(
987
0
    const common::UnitOfMeasure &angularUnit) const {
988
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
989
0
    if (l_axisList.size() == 2) {
990
0
        return EllipsoidalCS::create(util::PropertyMap(),
991
0
                                     l_axisList[0]->alterUnit(angularUnit),
992
0
                                     l_axisList[1]->alterUnit(angularUnit));
993
0
    } else {
994
0
        assert(l_axisList.size() == 3);
995
0
        return EllipsoidalCS::create(
996
0
            util::PropertyMap(), l_axisList[0]->alterUnit(angularUnit),
997
0
            l_axisList[1]->alterUnit(angularUnit), l_axisList[2]);
998
0
    }
999
0
}
1000
//! @endcond
1001
1002
// ---------------------------------------------------------------------------
1003
1004
//! @cond Doxygen_Suppress
1005
EllipsoidalCSNNPtr
1006
0
EllipsoidalCS::alterLinearUnit(const common::UnitOfMeasure &linearUnit) const {
1007
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
1008
0
    if (l_axisList.size() == 2) {
1009
0
        return EllipsoidalCS::create(util::PropertyMap(), l_axisList[0],
1010
0
                                     l_axisList[1]);
1011
0
    } else {
1012
0
        assert(l_axisList.size() == 3);
1013
0
        return EllipsoidalCS::create(util::PropertyMap(), l_axisList[0],
1014
0
                                     l_axisList[1],
1015
0
                                     l_axisList[2]->alterUnit(linearUnit));
1016
0
    }
1017
0
}
1018
//! @endcond
1019
1020
// ---------------------------------------------------------------------------
1021
1022
//! @cond Doxygen_Suppress
1023
VerticalCS::~VerticalCS() = default;
1024
//! @endcond
1025
1026
// ---------------------------------------------------------------------------
1027
1028
//! @cond Doxygen_Suppress
1029
VerticalCS::VerticalCS(const CoordinateSystemAxisNNPtr &axisIn)
1030
9.90k
    : CoordinateSystem(std::vector<CoordinateSystemAxisNNPtr>{axisIn}) {}
1031
//! @endcond
1032
1033
// ---------------------------------------------------------------------------
1034
1035
#ifdef notdef
1036
VerticalCS::VerticalCS(const VerticalCS &) = default;
1037
#endif
1038
1039
// ---------------------------------------------------------------------------
1040
1041
/** \brief Instantiate a VerticalCS.
1042
 *
1043
 * @param properties See \ref general_properties.
1044
 * @param axis The axis.
1045
 * @return a new VerticalCS.
1046
 */
1047
VerticalCSNNPtr VerticalCS::create(const util::PropertyMap &properties,
1048
652
                                   const CoordinateSystemAxisNNPtr &axis) {
1049
652
    auto cs(VerticalCS::nn_make_shared<VerticalCS>(axis));
1050
652
    cs->setProperties(properties);
1051
652
    return cs;
1052
652
}
1053
1054
// ---------------------------------------------------------------------------
1055
1056
/** \brief Instantiate a VerticalCS with a Gravity-related height axis
1057
 *
1058
 * @param unit linear unit.
1059
 * @return a new VerticalCS.
1060
 */
1061
VerticalCSNNPtr
1062
9.25k
VerticalCS::createGravityRelatedHeight(const common::UnitOfMeasure &unit) {
1063
9.25k
    auto cs(VerticalCS::nn_make_shared<VerticalCS>(CoordinateSystemAxis::create(
1064
9.25k
        util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1065
9.25k
                                "Gravity-related height"),
1066
9.25k
        "H", AxisDirection::UP, unit)));
1067
9.25k
    return cs;
1068
9.25k
}
1069
1070
// ---------------------------------------------------------------------------
1071
1072
//! @cond Doxygen_Suppress
1073
0
VerticalCSNNPtr VerticalCS::alterUnit(const common::UnitOfMeasure &unit) const {
1074
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
1075
0
    return VerticalCS::nn_make_shared<VerticalCS>(
1076
0
        l_axisList[0]->alterUnit(unit));
1077
0
}
1078
//! @endcond
1079
1080
// ---------------------------------------------------------------------------
1081
1082
//! @cond Doxygen_Suppress
1083
CartesianCS::~CartesianCS() = default;
1084
//! @endcond
1085
1086
// ---------------------------------------------------------------------------
1087
1088
CartesianCS::CartesianCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
1089
38.8k
    : CoordinateSystem(axisIn) {}
1090
1091
// ---------------------------------------------------------------------------
1092
1093
#ifdef notdef
1094
CartesianCS::CartesianCS(const CartesianCS &) = default;
1095
#endif
1096
1097
// ---------------------------------------------------------------------------
1098
1099
/** \brief Instantiate a CartesianCS.
1100
 *
1101
 * @param properties See \ref general_properties.
1102
 * @param axis1 The first axis.
1103
 * @param axis2 The second axis.
1104
 * @return a new CartesianCS.
1105
 */
1106
CartesianCSNNPtr CartesianCS::create(const util::PropertyMap &properties,
1107
                                     const CoordinateSystemAxisNNPtr &axis1,
1108
34.0k
                                     const CoordinateSystemAxisNNPtr &axis2) {
1109
34.0k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
1110
34.0k
    auto cs(CartesianCS::nn_make_shared<CartesianCS>(axis));
1111
34.0k
    cs->setProperties(properties);
1112
34.0k
    return cs;
1113
34.0k
}
1114
1115
// ---------------------------------------------------------------------------
1116
1117
/** \brief Instantiate a CartesianCS.
1118
 *
1119
 * @param properties See \ref general_properties.
1120
 * @param axis1 The first axis.
1121
 * @param axis2 The second axis.
1122
 * @param axis3 The third axis.
1123
 * @return a new CartesianCS.
1124
 */
1125
CartesianCSNNPtr CartesianCS::create(const util::PropertyMap &properties,
1126
                                     const CoordinateSystemAxisNNPtr &axis1,
1127
                                     const CoordinateSystemAxisNNPtr &axis2,
1128
4.82k
                                     const CoordinateSystemAxisNNPtr &axis3) {
1129
4.82k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
1130
4.82k
    auto cs(CartesianCS::nn_make_shared<CartesianCS>(axis));
1131
4.82k
    cs->setProperties(properties);
1132
4.82k
    return cs;
1133
4.82k
}
1134
1135
// ---------------------------------------------------------------------------
1136
1137
/** \brief Instantiate a CartesianCS with a Easting (first) and Northing
1138
 * (second) axis.
1139
 *
1140
 * @param unit Linear unit of the axes.
1141
 * @return a new CartesianCS.
1142
 */
1143
CartesianCSNNPtr
1144
4.42k
CartesianCS::createEastingNorthing(const common::UnitOfMeasure &unit) {
1145
4.42k
    return create(util::PropertyMap(),
1146
4.42k
                  CoordinateSystemAxis::create(
1147
4.42k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1148
4.42k
                                              AxisName::Easting),
1149
4.42k
                      AxisAbbreviation::E, AxisDirection::EAST, unit),
1150
4.42k
                  CoordinateSystemAxis::create(
1151
4.42k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1152
4.42k
                                              AxisName::Northing),
1153
4.42k
                      AxisAbbreviation::N, AxisDirection::NORTH, unit));
1154
4.42k
}
1155
1156
// ---------------------------------------------------------------------------
1157
1158
/** \brief Instantiate a CartesianCS with a Northing (first) and Easting
1159
 * (second) axis.
1160
 *
1161
 * @param unit Linear unit of the axes.
1162
 * @return a new CartesianCS.
1163
 */
1164
CartesianCSNNPtr
1165
0
CartesianCS::createNorthingEasting(const common::UnitOfMeasure &unit) {
1166
0
    return create(util::PropertyMap(),
1167
0
                  CoordinateSystemAxis::create(
1168
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1169
0
                                              AxisName::Northing),
1170
0
                      AxisAbbreviation::N, AxisDirection::NORTH, unit),
1171
0
                  CoordinateSystemAxis::create(
1172
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1173
0
                                              AxisName::Easting),
1174
0
                      AxisAbbreviation::E, AxisDirection::EAST, unit));
1175
0
}
1176
1177
// ---------------------------------------------------------------------------
1178
1179
/** \brief Instantiate a CartesianCS with a Westing (first) and Southing
1180
 * (second) axis.
1181
 *
1182
 * @param unit Linear unit of the axes.
1183
 * @return a new CartesianCS.
1184
 */
1185
CartesianCSNNPtr
1186
0
CartesianCS::createWestingSouthing(const common::UnitOfMeasure &unit) {
1187
0
    return create(util::PropertyMap(),
1188
0
                  CoordinateSystemAxis::create(
1189
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1190
0
                                              AxisName::Easting),
1191
0
                      AxisAbbreviation::Y, AxisDirection::WEST, unit),
1192
0
                  CoordinateSystemAxis::create(
1193
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1194
0
                                              AxisName::Northing),
1195
0
                      AxisAbbreviation::X, AxisDirection::SOUTH, unit));
1196
0
}
1197
1198
// ---------------------------------------------------------------------------
1199
1200
/** \brief Instantiate a CartesianCS, north-pole centered,
1201
 * with a Easting (first) South-Oriented and
1202
 * Northing (second) South-Oriented axis.
1203
 *
1204
 * @param unit Linear unit of the axes.
1205
 * @return a new CartesianCS.
1206
 */
1207
CartesianCSNNPtr CartesianCS::createNorthPoleEastingSouthNorthingSouth(
1208
7
    const common::UnitOfMeasure &unit) {
1209
7
    return create(util::PropertyMap(),
1210
7
                  CoordinateSystemAxis::create(
1211
7
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1212
7
                                              AxisName::Easting),
1213
7
                      AxisAbbreviation::E, AxisDirection::SOUTH, unit,
1214
7
                      Meridian::create(common::Angle(90))),
1215
7
                  CoordinateSystemAxis::create(
1216
7
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1217
7
                                              AxisName::Northing),
1218
7
                      AxisAbbreviation::N, AxisDirection::SOUTH, unit,
1219
7
                      Meridian::create(common::Angle(180))));
1220
7
}
1221
1222
// ---------------------------------------------------------------------------
1223
1224
/** \brief Instantiate a CartesianCS, south-pole centered,
1225
 * with a Easting (first) North-Oriented and
1226
 * Northing (second) North-Oriented axis.
1227
 *
1228
 * @param unit Linear unit of the axes.
1229
 * @return a new CartesianCS.
1230
 */
1231
CartesianCSNNPtr CartesianCS::createSouthPoleEastingNorthNorthingNorth(
1232
0
    const common::UnitOfMeasure &unit) {
1233
0
    return create(util::PropertyMap(),
1234
0
                  CoordinateSystemAxis::create(
1235
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1236
0
                                              AxisName::Easting),
1237
0
                      AxisAbbreviation::E, AxisDirection::NORTH, unit,
1238
0
                      Meridian::create(common::Angle(90))),
1239
0
                  CoordinateSystemAxis::create(
1240
0
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1241
0
                                              AxisName::Northing),
1242
0
                      AxisAbbreviation::N, AxisDirection::NORTH, unit,
1243
0
                      Meridian::create(common::Angle(0))));
1244
0
}
1245
1246
// ---------------------------------------------------------------------------
1247
1248
/** \brief Instantiate a CartesianCS with the three geocentric axes.
1249
 *
1250
 * @param unit Linear unit of the axes.
1251
 * @return a new CartesianCS.
1252
 */
1253
CartesianCSNNPtr
1254
3.62k
CartesianCS::createGeocentric(const common::UnitOfMeasure &unit) {
1255
3.62k
    return create(util::PropertyMap(),
1256
3.62k
                  CoordinateSystemAxis::create(
1257
3.62k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1258
3.62k
                                              AxisName::Geocentric_X),
1259
3.62k
                      AxisAbbreviation::X, AxisDirection::GEOCENTRIC_X, unit),
1260
3.62k
                  CoordinateSystemAxis::create(
1261
3.62k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1262
3.62k
                                              AxisName::Geocentric_Y),
1263
3.62k
                      AxisAbbreviation::Y, AxisDirection::GEOCENTRIC_Y, unit),
1264
3.62k
                  CoordinateSystemAxis::create(
1265
3.62k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1266
3.62k
                                              AxisName::Geocentric_Z),
1267
3.62k
                      AxisAbbreviation::Z, AxisDirection::GEOCENTRIC_Z, unit));
1268
3.62k
}
1269
1270
// ---------------------------------------------------------------------------
1271
1272
//! @cond Doxygen_Suppress
1273
CartesianCSNNPtr
1274
0
CartesianCS::alterUnit(const common::UnitOfMeasure &unit) const {
1275
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
1276
0
    if (l_axisList.size() == 2) {
1277
0
        return CartesianCS::create(util::PropertyMap(),
1278
0
                                   l_axisList[0]->alterUnit(unit),
1279
0
                                   l_axisList[1]->alterUnit(unit));
1280
0
    } else {
1281
0
        assert(l_axisList.size() == 3);
1282
0
        return CartesianCS::create(
1283
0
            util::PropertyMap(), l_axisList[0]->alterUnit(unit),
1284
0
            l_axisList[1]->alterUnit(unit), l_axisList[2]->alterUnit(unit));
1285
0
    }
1286
0
}
1287
//! @endcond
1288
1289
// ---------------------------------------------------------------------------
1290
1291
//! @cond Doxygen_Suppress
1292
AffineCS::~AffineCS() = default;
1293
//! @endcond
1294
1295
// ---------------------------------------------------------------------------
1296
1297
AffineCS::AffineCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
1298
0
    : CoordinateSystem(axisIn) {}
1299
1300
// ---------------------------------------------------------------------------
1301
1302
/** \brief Instantiate a AffineCS.
1303
 *
1304
 * @param properties See \ref general_properties.
1305
 * @param axis1 The first axis.
1306
 * @param axis2 The second axis.
1307
 * @return a new AffineCS.
1308
 */
1309
AffineCSNNPtr AffineCS::create(const util::PropertyMap &properties,
1310
                               const CoordinateSystemAxisNNPtr &axis1,
1311
0
                               const CoordinateSystemAxisNNPtr &axis2) {
1312
0
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
1313
0
    auto cs(AffineCS::nn_make_shared<AffineCS>(axis));
1314
0
    cs->setProperties(properties);
1315
0
    return cs;
1316
0
}
1317
1318
// ---------------------------------------------------------------------------
1319
1320
/** \brief Instantiate a AffineCS.
1321
 *
1322
 * @param properties See \ref general_properties.
1323
 * @param axis1 The first axis.
1324
 * @param axis2 The second axis.
1325
 * @param axis3 The third axis.
1326
 * @return a new AffineCS.
1327
 */
1328
AffineCSNNPtr AffineCS::create(const util::PropertyMap &properties,
1329
                               const CoordinateSystemAxisNNPtr &axis1,
1330
                               const CoordinateSystemAxisNNPtr &axis2,
1331
0
                               const CoordinateSystemAxisNNPtr &axis3) {
1332
0
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
1333
0
    auto cs(AffineCS::nn_make_shared<AffineCS>(axis));
1334
0
    cs->setProperties(properties);
1335
0
    return cs;
1336
0
}
1337
1338
// ---------------------------------------------------------------------------
1339
1340
//! @cond Doxygen_Suppress
1341
0
AffineCSNNPtr AffineCS::alterUnit(const common::UnitOfMeasure &unit) const {
1342
0
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
1343
0
    if (l_axisList.size() == 2) {
1344
0
        return AffineCS::create(util::PropertyMap(),
1345
0
                                l_axisList[0]->alterUnit(unit),
1346
0
                                l_axisList[1]->alterUnit(unit));
1347
0
    } else {
1348
0
        assert(l_axisList.size() == 3);
1349
0
        return AffineCS::create(
1350
0
            util::PropertyMap(), l_axisList[0]->alterUnit(unit),
1351
0
            l_axisList[1]->alterUnit(unit), l_axisList[2]->alterUnit(unit));
1352
0
    }
1353
0
}
1354
//! @endcond
1355
1356
// ---------------------------------------------------------------------------
1357
1358
//! @cond Doxygen_Suppress
1359
OrdinalCS::~OrdinalCS() = default;
1360
//! @endcond
1361
1362
// ---------------------------------------------------------------------------
1363
1364
OrdinalCS::OrdinalCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
1365
0
    : CoordinateSystem(axisIn) {}
1366
1367
// ---------------------------------------------------------------------------
1368
1369
#ifdef notdef
1370
OrdinalCS::OrdinalCS(const OrdinalCS &) = default;
1371
#endif
1372
1373
// ---------------------------------------------------------------------------
1374
1375
/** \brief Instantiate a OrdinalCS.
1376
 *
1377
 * @param properties See \ref general_properties.
1378
 * @param axisIn List of axis.
1379
 * @return a new OrdinalCS.
1380
 */
1381
OrdinalCSNNPtr
1382
OrdinalCS::create(const util::PropertyMap &properties,
1383
0
                  const std::vector<CoordinateSystemAxisNNPtr> &axisIn) {
1384
0
    auto cs(OrdinalCS::nn_make_shared<OrdinalCS>(axisIn));
1385
0
    cs->setProperties(properties);
1386
0
    return cs;
1387
0
}
1388
1389
// ---------------------------------------------------------------------------
1390
1391
//! @cond Doxygen_Suppress
1392
ParametricCS::~ParametricCS() = default;
1393
//! @endcond
1394
1395
// ---------------------------------------------------------------------------
1396
1397
ParametricCS::ParametricCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
1398
0
    : CoordinateSystem(axisIn) {}
1399
1400
// ---------------------------------------------------------------------------
1401
1402
#ifdef notdef
1403
ParametricCS::ParametricCS(const ParametricCS &) = default;
1404
#endif
1405
1406
// ---------------------------------------------------------------------------
1407
1408
/** \brief Instantiate a ParametricCS.
1409
 *
1410
 * @param properties See \ref general_properties.
1411
 * @param axisIn Axis.
1412
 * @return a new ParametricCS.
1413
 */
1414
ParametricCSNNPtr
1415
ParametricCS::create(const util::PropertyMap &properties,
1416
0
                     const CoordinateSystemAxisNNPtr &axisIn) {
1417
0
    auto cs(ParametricCS::nn_make_shared<ParametricCS>(
1418
0
        std::vector<CoordinateSystemAxisNNPtr>{axisIn}));
1419
0
    cs->setProperties(properties);
1420
0
    return cs;
1421
0
}
1422
1423
// ---------------------------------------------------------------------------
1424
1425
240
AxisDirection::AxisDirection(const std::string &nameIn) : CodeList(nameIn) {
1426
240
    auto lowerName = tolower(nameIn);
1427
240
    assert(registry.find(lowerName) == registry.end());
1428
240
    registry[lowerName] = this;
1429
240
}
1430
1431
// ---------------------------------------------------------------------------
1432
1433
//! @cond Doxygen_Suppress
1434
const AxisDirection *
1435
642
AxisDirection::valueOf(const std::string &nameIn) noexcept {
1436
642
    auto iter = registry.find(tolower(nameIn));
1437
642
    if (iter == registry.end())
1438
92
        return nullptr;
1439
550
    return iter->second;
1440
642
}
1441
//! @endcond
1442
1443
// ---------------------------------------------------------------------------
1444
1445
12
RangeMeaning::RangeMeaning(const std::string &nameIn) : CodeList(nameIn) {
1446
12
    auto lowerName = tolower(nameIn);
1447
12
    assert(registry.find(lowerName) == registry.end());
1448
12
    registry[lowerName] = this;
1449
12
}
1450
1451
// ---------------------------------------------------------------------------
1452
1453
443k
RangeMeaning::RangeMeaning() : CodeList(std::string()) {}
1454
1455
// ---------------------------------------------------------------------------
1456
1457
//! @cond Doxygen_Suppress
1458
95
const RangeMeaning *RangeMeaning::valueOf(const std::string &nameIn) noexcept {
1459
95
    auto iter = registry.find(tolower(nameIn));
1460
95
    if (iter == registry.end())
1461
7
        return nullptr;
1462
88
    return iter->second;
1463
95
}
1464
//! @endcond
1465
1466
//! @cond Doxygen_Suppress
1467
// ---------------------------------------------------------------------------
1468
1469
AxisDirectionWKT1::AxisDirectionWKT1(const std::string &nameIn)
1470
42
    : CodeList(nameIn) {
1471
42
    auto lowerName = tolower(nameIn);
1472
42
    assert(registry.find(lowerName) == registry.end());
1473
42
    registry[lowerName] = this;
1474
42
}
1475
1476
// ---------------------------------------------------------------------------
1477
1478
0
const AxisDirectionWKT1 *AxisDirectionWKT1::valueOf(const std::string &nameIn) {
1479
0
    auto iter = registry.find(tolower(nameIn));
1480
0
    if (iter == registry.end())
1481
0
        return nullptr;
1482
0
    return iter->second;
1483
0
}
1484
1485
//! @endcond
1486
1487
// ---------------------------------------------------------------------------
1488
1489
//! @cond Doxygen_Suppress
1490
TemporalCS::~TemporalCS() = default;
1491
//! @endcond
1492
1493
// ---------------------------------------------------------------------------
1494
1495
//! @cond Doxygen_Suppress
1496
TemporalCS::TemporalCS(const CoordinateSystemAxisNNPtr &axisIn)
1497
77
    : CoordinateSystem(std::vector<CoordinateSystemAxisNNPtr>{axisIn}) {}
1498
//! @endcond
1499
1500
// ---------------------------------------------------------------------------
1501
1502
//! @cond Doxygen_Suppress
1503
DateTimeTemporalCS::~DateTimeTemporalCS() = default;
1504
//! @endcond
1505
1506
// ---------------------------------------------------------------------------
1507
1508
DateTimeTemporalCS::DateTimeTemporalCS(const CoordinateSystemAxisNNPtr &axisIn)
1509
0
    : TemporalCS(axisIn) {}
1510
1511
// ---------------------------------------------------------------------------
1512
1513
/** \brief Instantiate a DateTimeTemporalCS.
1514
 *
1515
 * @param properties See \ref general_properties.
1516
 * @param axisIn The axis.
1517
 * @return a new DateTimeTemporalCS.
1518
 */
1519
DateTimeTemporalCSNNPtr
1520
DateTimeTemporalCS::create(const util::PropertyMap &properties,
1521
0
                           const CoordinateSystemAxisNNPtr &axisIn) {
1522
0
    auto cs(DateTimeTemporalCS::nn_make_shared<DateTimeTemporalCS>(axisIn));
1523
0
    cs->setProperties(properties);
1524
0
    return cs;
1525
0
}
1526
1527
// ---------------------------------------------------------------------------
1528
1529
0
std::string DateTimeTemporalCS::getWKT2Type(bool use2019Keywords) const {
1530
0
    return use2019Keywords ? WKT2_2019_TYPE : WKT2_2015_TYPE;
1531
0
}
1532
1533
// ---------------------------------------------------------------------------
1534
1535
//! @cond Doxygen_Suppress
1536
TemporalCountCS::~TemporalCountCS() = default;
1537
//! @endcond
1538
1539
// ---------------------------------------------------------------------------
1540
1541
TemporalCountCS::TemporalCountCS(const CoordinateSystemAxisNNPtr &axisIn)
1542
77
    : TemporalCS(axisIn) {}
1543
1544
// ---------------------------------------------------------------------------
1545
1546
/** \brief Instantiate a TemporalCountCS.
1547
 *
1548
 * @param properties See \ref general_properties.
1549
 * @param axisIn The axis.
1550
 * @return a new TemporalCountCS.
1551
 */
1552
TemporalCountCSNNPtr
1553
TemporalCountCS::create(const util::PropertyMap &properties,
1554
77
                        const CoordinateSystemAxisNNPtr &axisIn) {
1555
77
    auto cs(TemporalCountCS::nn_make_shared<TemporalCountCS>(axisIn));
1556
77
    cs->setProperties(properties);
1557
77
    return cs;
1558
77
}
1559
1560
// ---------------------------------------------------------------------------
1561
1562
0
std::string TemporalCountCS::getWKT2Type(bool use2019Keywords) const {
1563
0
    return use2019Keywords ? WKT2_2019_TYPE : WKT2_2015_TYPE;
1564
0
}
1565
1566
// ---------------------------------------------------------------------------
1567
1568
//! @cond Doxygen_Suppress
1569
TemporalMeasureCS::~TemporalMeasureCS() = default;
1570
//! @endcond
1571
1572
// ---------------------------------------------------------------------------
1573
1574
TemporalMeasureCS::TemporalMeasureCS(const CoordinateSystemAxisNNPtr &axisIn)
1575
0
    : TemporalCS(axisIn) {}
1576
1577
// ---------------------------------------------------------------------------
1578
1579
/** \brief Instantiate a TemporalMeasureCS.
1580
 *
1581
 * @param properties See \ref general_properties.
1582
 * @param axisIn The axis.
1583
 * @return a new TemporalMeasureCS.
1584
 */
1585
TemporalMeasureCSNNPtr
1586
TemporalMeasureCS::create(const util::PropertyMap &properties,
1587
0
                          const CoordinateSystemAxisNNPtr &axisIn) {
1588
0
    auto cs(TemporalMeasureCS::nn_make_shared<TemporalMeasureCS>(axisIn));
1589
0
    cs->setProperties(properties);
1590
0
    return cs;
1591
0
}
1592
1593
// ---------------------------------------------------------------------------
1594
1595
0
std::string TemporalMeasureCS::getWKT2Type(bool use2019Keywords) const {
1596
0
    return use2019Keywords ? WKT2_2019_TYPE : WKT2_2015_TYPE;
1597
0
}
1598
1599
} // namespace cs
1600
NS_PROJ_END