Coverage Report

Created: 2026-01-09 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/iso19111/coordinatesystem.cpp
Line
Count
Source
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
308
    explicit Private(const common::Angle &longitude) : longitude_(longitude) {}
81
};
82
//! @endcond
83
84
// ---------------------------------------------------------------------------
85
86
Meridian::Meridian(const common::Angle &longitudeIn)
87
308
    : 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
308
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
308
MeridianNNPtr Meridian::create(const common::Angle &longitudeIn) {
122
308
    return Meridian::nn_make_shared<Meridian>(longitudeIn);
123
308
}
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
343k
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
343k
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
4
const std::string &CoordinateSystemAxis::abbreviation() PROJ_PURE_DEFN {
211
4
    return d->abbreviation;
212
4
}
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
5.08M
const AxisDirection &CoordinateSystemAxis::direction() PROJ_PURE_DEFN {
232
5.08M
    return *(d->direction);
233
5.08M
}
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
2.42M
const common::UnitOfMeasure &CoordinateSystemAxis::unit() PROJ_PURE_DEFN {
246
2.42M
    return d->unit;
247
2.42M
}
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
343k
    const MeridianPtr &meridianIn) {
315
343k
    auto csa(CoordinateSystemAxis::nn_make_shared<CoordinateSystemAxis>());
316
343k
    csa->setProperties(properties);
317
343k
    csa->d->abbreviation = abbreviationIn;
318
343k
    csa->d->direction = &directionIn;
319
343k
    csa->d->unit = unitIn;
320
343k
    csa->d->meridian = meridianIn;
321
343k
    return csa;
322
343k
}
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
60
    const MeridianPtr &meridianIn) {
349
60
    auto csa(CoordinateSystemAxis::nn_make_shared<CoordinateSystemAxis>());
350
60
    csa->setProperties(properties);
351
60
    csa->d->abbreviation = abbreviationIn;
352
60
    csa->d->direction = &directionIn;
353
60
    csa->d->unit = unitIn;
354
60
    csa->d->minimumValue = minimumValueIn;
355
60
    csa->d->maximumValue = maximumValueIn;
356
60
    csa->d->rangeMeaning = rangeMeaningIn;
357
60
    csa->d->meridian = meridianIn;
358
60
    return csa;
359
60
}
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
155
std::string CoordinateSystemAxis::normalizeAxisName(const std::string &str) {
376
155
    if (str.empty()) {
377
3
        return str;
378
3
    }
379
    // on import, transform from WKT2 "longitude" to "Longitude", as in the
380
    // EPSG database.
381
152
    return toupper(str.substr(0, 1)) + str.substr(1);
382
155
}
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
2.27M
    const io::DatabaseContextPtr &dbContext) const {
554
2.27M
    auto otherCSA = dynamic_cast<const CoordinateSystemAxis *>(other);
555
2.27M
    if (otherCSA == nullptr) {
556
0
        return false;
557
0
    }
558
    // For approximate comparison, only care about axis direction and unit.
559
2.27M
    if (!(*(d->direction) == *(otherCSA->d->direction) &&
560
2.23M
          d->unit._isEquivalentTo(otherCSA->d->unit, criterion))) {
561
42.4k
        return false;
562
42.4k
    }
563
2.23M
    if (criterion == util::IComparable::Criterion::STRICT) {
564
2
        if (!IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) {
565
0
            return false;
566
0
        }
567
2
        if (abbreviation() != otherCSA->abbreviation()) {
568
0
            return false;
569
0
        }
570
        // TODO other metadata
571
2
    }
572
573
2.23M
    return true;
574
2.23M
}
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
180k
        : axisList(axisListIn) {}
595
};
596
//! @endcond
597
598
// ---------------------------------------------------------------------------
599
600
CoordinateSystem::CoordinateSystem(
601
    const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
602
180k
    : 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
180k
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
9.31M
CoordinateSystem::axisList() PROJ_PURE_DEFN {
625
9.31M
    return d->axisList;
626
9.31M
}
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
1.03M
    const io::DatabaseContextPtr &dbContext) const {
726
1.03M
    auto otherCS = dynamic_cast<const CoordinateSystem *>(other);
727
1.03M
    if (otherCS == nullptr ||
728
1.03M
        !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) {
729
0
        return false;
730
0
    }
731
1.03M
    const auto &list = axisList();
732
1.03M
    const auto &otherList = otherCS->axisList();
733
1.03M
    if (list.size() != otherList.size()) {
734
99.9k
        return false;
735
99.9k
    }
736
936k
    if (getWKT2Type(true) != otherCS->getWKT2Type(true)) {
737
0
        return false;
738
0
    }
739
3.11M
    for (size_t i = 0; i < list.size(); i++) {
740
2.21M
        if (!list[i]->_isEquivalentTo(otherList[i].get(), criterion,
741
2.21M
                                      dbContext)) {
742
41.0k
            return false;
743
41.0k
        }
744
2.21M
    }
745
895k
    return true;
746
936k
}
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
318
    : 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
318
                                     const CoordinateSystemAxisNNPtr &axis2) {
801
318
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
802
318
    auto cs(SphericalCS::nn_make_shared<SphericalCS>(axis));
803
318
    cs->setProperties(properties);
804
318
    return cs;
805
318
}
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
137k
    : 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
97.0k
                      const CoordinateSystemAxisNNPtr &axis2) {
838
97.0k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
839
97.0k
    auto cs(EllipsoidalCS::nn_make_shared<EllipsoidalCS>(axis));
840
97.0k
    cs->setProperties(properties);
841
97.0k
    return cs;
842
97.0k
}
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
40.7k
                      const CoordinateSystemAxisNNPtr &axis3) {
859
40.7k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
860
40.7k
    auto cs(EllipsoidalCS::nn_make_shared<EllipsoidalCS>(axis));
861
40.7k
    cs->setProperties(properties);
862
40.7k
    return cs;
863
40.7k
}
864
865
// ---------------------------------------------------------------------------
866
867
//! @cond Doxygen_Suppress
868
CoordinateSystemAxisNNPtr
869
20.7k
CoordinateSystemAxis::createLAT_NORTH(const common::UnitOfMeasure &unit) {
870
20.7k
    return create(
871
20.7k
        util::PropertyMap().set(IdentifiedObject::NAME_KEY, AxisName::Latitude),
872
20.7k
        AxisAbbreviation::lat, AxisDirection::NORTH, unit);
873
20.7k
}
874
875
CoordinateSystemAxisNNPtr
876
20.7k
CoordinateSystemAxis::createLONG_EAST(const common::UnitOfMeasure &unit) {
877
20.7k
    return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY,
878
20.7k
                                          AxisName::Longitude),
879
20.7k
                  AxisAbbreviation::lon, AxisDirection::EAST, unit);
880
20.7k
}
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
639
EllipsoidalCS::createLatitudeLongitude(const common::UnitOfMeasure &unit) {
893
639
    return EllipsoidalCS::create(util::PropertyMap(),
894
639
                                 CoordinateSystemAxis::createLAT_NORTH(unit),
895
639
                                 CoordinateSystemAxis::createLONG_EAST(unit));
896
639
}
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
1.10k
    const common::UnitOfMeasure &linearUnit) {
910
1.10k
    return EllipsoidalCS::create(
911
1.10k
        util::PropertyMap(), CoordinateSystemAxis::createLAT_NORTH(angularUnit),
912
1.10k
        CoordinateSystemAxis::createLONG_EAST(angularUnit),
913
1.10k
        CoordinateSystemAxis::create(
914
1.10k
            util::PropertyMap().set(IdentifiedObject::NAME_KEY,
915
1.10k
                                    AxisName::Ellipsoidal_height),
916
1.10k
            AxisAbbreviation::h, AxisDirection::UP, linearUnit));
917
1.10k
}
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
4.58k
EllipsoidalCS::createLongitudeLatitude(const common::UnitOfMeasure &unit) {
929
4.58k
    return EllipsoidalCS::create(util::PropertyMap(),
930
4.58k
                                 CoordinateSystemAxis::createLONG_EAST(unit),
931
4.58k
                                 CoordinateSystemAxis::createLAT_NORTH(unit));
932
4.58k
}
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
14.4k
    const common::UnitOfMeasure &linearUnit) {
947
14.4k
    return EllipsoidalCS::create(
948
14.4k
        util::PropertyMap(), CoordinateSystemAxis::createLONG_EAST(angularUnit),
949
14.4k
        CoordinateSystemAxis::createLAT_NORTH(angularUnit),
950
14.4k
        CoordinateSystemAxis::create(
951
14.4k
            util::PropertyMap().set(IdentifiedObject::NAME_KEY,
952
14.4k
                                    AxisName::Ellipsoidal_height),
953
14.4k
            AxisAbbreviation::h, AxisDirection::UP, linearUnit));
954
14.4k
}
955
956
// ---------------------------------------------------------------------------
957
958
//! @cond Doxygen_Suppress
959
/** \brief Return the axis order in an enumerated way. */
960
175k
EllipsoidalCS::AxisOrder EllipsoidalCS::axisOrder() const {
961
175k
    const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
962
175k
    const auto &dir0 = l_axisList[0]->direction();
963
175k
    const auto &dir1 = l_axisList[1]->direction();
964
175k
    if (&dir0 == &AxisDirection::NORTH && &dir1 == &AxisDirection::EAST) {
965
98.3k
        if (l_axisList.size() == 2) {
966
53.4k
            return AxisOrder::LAT_NORTH_LONG_EAST;
967
53.4k
        } else if (&l_axisList[2]->direction() == &AxisDirection::UP) {
968
44.9k
            return AxisOrder::LAT_NORTH_LONG_EAST_HEIGHT_UP;
969
44.9k
        }
970
98.3k
    } else if (&dir0 == &AxisDirection::EAST &&
971
76.4k
               &dir1 == &AxisDirection::NORTH) {
972
76.4k
        if (l_axisList.size() == 2) {
973
37.7k
            return AxisOrder::LONG_EAST_LAT_NORTH;
974
38.7k
        } else if (&l_axisList[2]->direction() == &AxisDirection::UP) {
975
38.7k
            return AxisOrder::LONG_EAST_LAT_NORTH_HEIGHT_UP;
976
38.7k
        }
977
76.4k
    }
978
979
438
    return AxisOrder::OTHER;
980
175k
}
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
20.0k
    : 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
671
                                   const CoordinateSystemAxisNNPtr &axis) {
1049
671
    auto cs(VerticalCS::nn_make_shared<VerticalCS>(axis));
1050
671
    cs->setProperties(properties);
1051
671
    return cs;
1052
671
}
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
19.3k
VerticalCS::createGravityRelatedHeight(const common::UnitOfMeasure &unit) {
1063
19.3k
    auto cs(VerticalCS::nn_make_shared<VerticalCS>(CoordinateSystemAxis::create(
1064
19.3k
        util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1065
19.3k
                                "Gravity-related height"),
1066
19.3k
        "H", AxisDirection::UP, unit)));
1067
19.3k
    return cs;
1068
19.3k
}
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
21.9k
    : 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
13.0k
                                     const CoordinateSystemAxisNNPtr &axis2) {
1109
13.0k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
1110
13.0k
    auto cs(CartesianCS::nn_make_shared<CartesianCS>(axis));
1111
13.0k
    cs->setProperties(properties);
1112
13.0k
    return cs;
1113
13.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
8.94k
                                     const CoordinateSystemAxisNNPtr &axis3) {
1129
8.94k
    std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
1130
8.94k
    auto cs(CartesianCS::nn_make_shared<CartesianCS>(axis));
1131
8.94k
    cs->setProperties(properties);
1132
8.94k
    return cs;
1133
8.94k
}
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
1.28k
CartesianCS::createEastingNorthing(const common::UnitOfMeasure &unit) {
1145
1.28k
    return create(util::PropertyMap(),
1146
1.28k
                  CoordinateSystemAxis::create(
1147
1.28k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1148
1.28k
                                              AxisName::Easting),
1149
1.28k
                      AxisAbbreviation::E, AxisDirection::EAST, unit),
1150
1.28k
                  CoordinateSystemAxis::create(
1151
1.28k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1152
1.28k
                                              AxisName::Northing),
1153
1.28k
                      AxisAbbreviation::N, AxisDirection::NORTH, unit));
1154
1.28k
}
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
16
    const common::UnitOfMeasure &unit) {
1209
16
    return create(util::PropertyMap(),
1210
16
                  CoordinateSystemAxis::create(
1211
16
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1212
16
                                              AxisName::Easting),
1213
16
                      AxisAbbreviation::E, AxisDirection::SOUTH, unit,
1214
16
                      Meridian::create(common::Angle(90))),
1215
16
                  CoordinateSystemAxis::create(
1216
16
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1217
16
                                              AxisName::Northing),
1218
16
                      AxisAbbreviation::N, AxisDirection::SOUTH, unit,
1219
16
                      Meridian::create(common::Angle(180))));
1220
16
}
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
9
    const common::UnitOfMeasure &unit) {
1233
9
    return create(util::PropertyMap(),
1234
9
                  CoordinateSystemAxis::create(
1235
9
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1236
9
                                              AxisName::Easting),
1237
9
                      AxisAbbreviation::E, AxisDirection::NORTH, unit,
1238
9
                      Meridian::create(common::Angle(90))),
1239
9
                  CoordinateSystemAxis::create(
1240
9
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1241
9
                                              AxisName::Northing),
1242
9
                      AxisAbbreviation::N, AxisDirection::NORTH, unit,
1243
9
                      Meridian::create(common::Angle(0))));
1244
9
}
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.05k
CartesianCS::createGeocentric(const common::UnitOfMeasure &unit) {
1255
3.05k
    return create(util::PropertyMap(),
1256
3.05k
                  CoordinateSystemAxis::create(
1257
3.05k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1258
3.05k
                                              AxisName::Geocentric_X),
1259
3.05k
                      AxisAbbreviation::X, AxisDirection::GEOCENTRIC_X, unit),
1260
3.05k
                  CoordinateSystemAxis::create(
1261
3.05k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1262
3.05k
                                              AxisName::Geocentric_Y),
1263
3.05k
                      AxisAbbreviation::Y, AxisDirection::GEOCENTRIC_Y, unit),
1264
3.05k
                  CoordinateSystemAxis::create(
1265
3.05k
                      util::PropertyMap().set(IdentifiedObject::NAME_KEY,
1266
3.05k
                                              AxisName::Geocentric_Z),
1267
3.05k
                      AxisAbbreviation::Z, AxisDirection::GEOCENTRIC_Z, unit));
1268
3.05k
}
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
80
AxisDirection::AxisDirection(const std::string &nameIn) : CodeList(nameIn) {
1426
80
    auto lowerName = tolower(nameIn);
1427
80
    assert(registry.find(lowerName) == registry.end());
1428
80
    registry[lowerName] = this;
1429
80
}
1430
1431
// ---------------------------------------------------------------------------
1432
1433
//! @cond Doxygen_Suppress
1434
const AxisDirection *
1435
53.3k
AxisDirection::valueOf(const std::string &nameIn) noexcept {
1436
53.3k
    auto iter = registry.find(tolower(nameIn));
1437
53.3k
    if (iter == registry.end())
1438
225
        return nullptr;
1439
53.0k
    return iter->second;
1440
53.3k
}
1441
//! @endcond
1442
1443
// ---------------------------------------------------------------------------
1444
1445
4
RangeMeaning::RangeMeaning(const std::string &nameIn) : CodeList(nameIn) {
1446
4
    auto lowerName = tolower(nameIn);
1447
4
    assert(registry.find(lowerName) == registry.end());
1448
4
    registry[lowerName] = this;
1449
4
}
1450
1451
// ---------------------------------------------------------------------------
1452
1453
343k
RangeMeaning::RangeMeaning() : CodeList(std::string()) {}
1454
1455
// ---------------------------------------------------------------------------
1456
1457
//! @cond Doxygen_Suppress
1458
8
const RangeMeaning *RangeMeaning::valueOf(const std::string &nameIn) noexcept {
1459
8
    auto iter = registry.find(tolower(nameIn));
1460
8
    if (iter == registry.end())
1461
8
        return nullptr;
1462
0
    return iter->second;
1463
8
}
1464
//! @endcond
1465
1466
//! @cond Doxygen_Suppress
1467
// ---------------------------------------------------------------------------
1468
1469
AxisDirectionWKT1::AxisDirectionWKT1(const std::string &nameIn)
1470
14
    : CodeList(nameIn) {
1471
14
    auto lowerName = tolower(nameIn);
1472
14
    assert(registry.find(lowerName) == registry.end());
1473
14
    registry[lowerName] = this;
1474
14
}
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
0
    : 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
0
    : 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
0
                        const CoordinateSystemAxisNNPtr &axisIn) {
1555
0
    auto cs(TemporalCountCS::nn_make_shared<TemporalCountCS>(axisIn));
1556
0
    cs->setProperties(properties);
1557
0
    return cs;
1558
0
}
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