diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2018-12-19 12:25:33 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2018-12-26 10:08:54 +0100 |
| commit | e6de172371ea203f6393d745641d66c82b5b13e2 (patch) | |
| tree | 791fa07f431a2d1db6f6e813ab984db982587278 /src/datum.cpp | |
| parent | ce8075076b4e4ffebd32afaba419e1d9ab27cd03 (diff) | |
| download | PROJ-e6de172371ea203f6393d745641d66c82b5b13e2.tar.gz PROJ-e6de172371ea203f6393d745641d66c82b5b13e2.zip | |
cpp conversion: move source files in apps/ iso19111/ conversions/ projections/ transformations/ tests/ subdirectories
Diffstat (limited to 'src/datum.cpp')
| -rw-r--r-- | src/datum.cpp | 1996 |
1 files changed, 0 insertions, 1996 deletions
diff --git a/src/datum.cpp b/src/datum.cpp deleted file mode 100644 index 16e86296..00000000 --- a/src/datum.cpp +++ /dev/null @@ -1,1996 +0,0 @@ -/****************************************************************************** - * - * Project: PROJ - * Purpose: ISO19111:2018 implementation - * Author: Even Rouault <even dot rouault at spatialys dot com> - * - ****************************************************************************** - * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef FROM_PROJ_CPP -#define FROM_PROJ_CPP -#endif - -#include "proj/datum.hpp" -#include "proj/common.hpp" -#include "proj/io.hpp" -#include "proj/metadata.hpp" -#include "proj/util.hpp" - -#include "proj/internal/internal.hpp" -#include "proj/internal/io_internal.hpp" - -// PROJ include order is sensitive -// clang-format off -#include "proj.h" -#include "projects.h" -#include "proj_api.h" -// clang-format on - -#include <cmath> -#include <cstdlib> -#include <memory> -#include <string> - -using namespace NS_PROJ::internal; - -#if 0 -namespace dropbox{ namespace oxygen { -template<> nn<NS_PROJ::datum::DatumPtr>::~nn() = default; -template<> nn<NS_PROJ::datum::DatumEnsemblePtr>::~nn() = default; -template<> nn<NS_PROJ::datum::PrimeMeridianPtr>::~nn() = default; -template<> nn<NS_PROJ::datum::EllipsoidPtr>::~nn() = default; -template<> nn<NS_PROJ::datum::GeodeticReferenceFramePtr>::~nn() = default; -template<> nn<NS_PROJ::datum::DynamicGeodeticReferenceFramePtr>::~nn() = default; -template<> nn<NS_PROJ::datum::VerticalReferenceFramePtr>::~nn() = default; -template<> nn<NS_PROJ::datum::DynamicVerticalReferenceFramePtr>::~nn() = default; -template<> nn<NS_PROJ::datum::EngineeringDatumPtr>::~nn() = default; -template<> nn<NS_PROJ::datum::TemporalDatumPtr>::~nn() = default; -template<> nn<NS_PROJ::datum::ParametricDatumPtr>::~nn() = default; -}} -#endif - -NS_PROJ_START -namespace datum { - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -static util::PropertyMap createMapNameEPSGCode(const char *name, int code) { - return util::PropertyMap() - .set(common::IdentifiedObject::NAME_KEY, name) - .set(metadata::Identifier::CODESPACE_KEY, metadata::Identifier::EPSG) - .set(metadata::Identifier::CODE_KEY, code); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct Datum::Private { - util::optional<std::string> anchorDefinition{}; - util::optional<common::DateTime> publicationDate{}; - common::IdentifiedObjectPtr conventionalRS{}; - - // cppcheck-suppress functionStatic - void exportAnchorDefinition(io::WKTFormatter *formatter) const; -}; - -// --------------------------------------------------------------------------- - -void Datum::Private::exportAnchorDefinition(io::WKTFormatter *formatter) const { - if (anchorDefinition) { - formatter->startNode(io::WKTConstants::ANCHOR, false); - formatter->addQuotedString(*anchorDefinition); - formatter->endNode(); - } -} - -//! @endcond - -// --------------------------------------------------------------------------- - -Datum::Datum() : d(internal::make_unique<Private>()) {} - -// --------------------------------------------------------------------------- - -#ifdef notdef -Datum::Datum(const Datum &other) - : ObjectUsage(other), d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -Datum::~Datum() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the anchor definition. - * - * A description - possibly including coordinates of an identified point or - * points - of the relationship used to anchor a coordinate system to the - * Earth or alternate object. - * <ul> - * <li>For modern geodetic reference frames the anchor may be a set of station - * coordinates; if the reference frame is dynamic it will also include - * coordinate velocities. For a traditional geodetic datum, this anchor may be - * a point known as the fundamental point, which is traditionally the point - * where the relationship between geoid and ellipsoid is defined, together - * with a direction from that point.</li> - * <li>For a vertical reference frame the anchor may be the zero level at one - * or more defined locations or a conventionally defined surface.</li> - * <li>For an engineering datum, the anchor may be an identified physical point - * with the orientation defined relative to the object.</li> - * </ul> - * - * @return the anchor definition, or empty. - */ -const util::optional<std::string> &Datum::anchorDefinition() const { - return d->anchorDefinition; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the date on which the datum definition was published. - * - * \note Departure from \ref ISO_19111_2018 : we return a DateTime instead of - * a Citation::Date. - * - * @return the publication date, or empty. - */ -const util::optional<common::DateTime> &Datum::publicationDate() const { - return d->publicationDate; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the conventional reference system. - * - * This is the name, identifier, alias and remarks for the terrestrial - * reference system or vertical reference system realized by this reference - * frame, for example "ITRS" for ITRF88 through ITRF2008 and ITRF2014, or - * "EVRS" for EVRF2000 and EVRF2007. - * - * @return the conventional reference system, or nullptr. - */ -const common::IdentifiedObjectPtr &Datum::conventionalRS() const { - return d->conventionalRS; -} - -// --------------------------------------------------------------------------- - -void Datum::setAnchor(const util::optional<std::string> &anchor) { - d->anchorDefinition = anchor; -} - -// --------------------------------------------------------------------------- - -bool Datum::__isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherDatum = dynamic_cast<const Datum *>(other); - if (otherDatum == nullptr || - !ObjectUsage::_isEquivalentTo(other, criterion)) { - return false; - } - if (criterion == util::IComparable::Criterion::STRICT) { - if ((anchorDefinition().has_value() ^ - otherDatum->anchorDefinition().has_value())) { - return false; - } - if (anchorDefinition().has_value() && - otherDatum->anchorDefinition().has_value() && - *anchorDefinition() != *otherDatum->anchorDefinition()) { - return false; - } - - if ((publicationDate().has_value() ^ - otherDatum->publicationDate().has_value())) { - return false; - } - if (publicationDate().has_value() && - otherDatum->publicationDate().has_value() && - publicationDate()->toString() != - otherDatum->publicationDate()->toString()) { - return false; - } - - if (((conventionalRS() != nullptr) ^ - (otherDatum->conventionalRS() != nullptr))) { - return false; - } - if (conventionalRS() && otherDatum->conventionalRS() && - conventionalRS()->_isEquivalentTo( - otherDatum->conventionalRS().get(), criterion)) { - return false; - } - } - return true; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct PrimeMeridian::Private { - common::Angle longitude_{}; - - explicit Private(const common::Angle &longitude) : longitude_(longitude) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -PrimeMeridian::PrimeMeridian(const common::Angle &longitudeIn) - : d(internal::make_unique<Private>(longitudeIn)) {} - -// --------------------------------------------------------------------------- - -#ifdef notdef -PrimeMeridian::PrimeMeridian(const PrimeMeridian &other) - : common::IdentifiedObject(other), - d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -PrimeMeridian::~PrimeMeridian() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the longitude of the prime meridian. - * - * It is measured from the internationally-recognised reference meridian - * ('Greenwich meridian'), positive eastward. - * The default value is 0 degrees. - * - * @return the longitude of the prime meridian. - */ -const common::Angle &PrimeMeridian::longitude() PROJ_CONST_DEFN { - return d->longitude_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a PrimeMeridian. - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param longitudeIn the longitude of the prime meridian. - * @return new PrimeMeridian. - */ -PrimeMeridianNNPtr PrimeMeridian::create(const util::PropertyMap &properties, - const common::Angle &longitudeIn) { - auto pm(PrimeMeridian::nn_make_shared<PrimeMeridian>(longitudeIn)); - pm->setProperties(properties); - return pm; -} - -// --------------------------------------------------------------------------- - -const PrimeMeridianNNPtr PrimeMeridian::createGREENWICH() { - return create(createMapNameEPSGCode("Greenwich", 8901), common::Angle(0)); -} - -// --------------------------------------------------------------------------- - -const PrimeMeridianNNPtr PrimeMeridian::createREFERENCE_MERIDIAN() { - return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY, - "Reference meridian"), - common::Angle(0)); -} - -// --------------------------------------------------------------------------- - -const PrimeMeridianNNPtr PrimeMeridian::createPARIS() { - return create(createMapNameEPSGCode("Paris", 8903), - common::Angle(2.5969213, common::UnitOfMeasure::GRAD)); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void PrimeMeridian::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - std::string l_name = - name()->description().has_value() ? nameStr() : "Greenwich"; - if (!(isWKT2 && formatter->primeMeridianOmittedIfGreenwich() && - l_name == "Greenwich")) { - formatter->startNode(io::WKTConstants::PRIMEM, !identifiers().empty()); - formatter->addQuotedString(l_name); - const auto &l_long = longitude(); - if (formatter->primeMeridianInDegree()) { - formatter->add(l_long.convertToUnit(common::UnitOfMeasure::DEGREE)); - } else { - formatter->add(l_long.value()); - } - const auto &unit = l_long.unit(); - if (isWKT2) { - if (!(formatter - ->primeMeridianOrParameterUnitOmittedIfSameAsAxis() && - unit == *(formatter->axisAngularUnit()))) { - unit._exportToWKT(formatter, io::WKTConstants::ANGLEUNIT); - } - } else if (!formatter->primeMeridianInDegree()) { - unit._exportToWKT(formatter); - } - if (formatter->outputId()) { - formatID(formatter); - } - formatter->endNode(); - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -std::string -PrimeMeridian::getPROJStringWellKnownName(const common::Angle &angle) { - const double valRad = angle.getSIValue(); - std::string projPMName; - projCtx ctxt = pj_ctx_alloc(); - auto proj_pm = proj_list_prime_meridians(); - for (int i = 0; proj_pm[i].id != nullptr; ++i) { - double valRefRad = dmstor_ctx(ctxt, proj_pm[i].defn, nullptr); - if (::fabs(valRad - valRefRad) < 1e-10) { - projPMName = proj_pm[i].id; - break; - } - } - pj_ctx_free(ctxt); - return projPMName; -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void PrimeMeridian::_exportToPROJString( - io::PROJStringFormatter *formatter) const // throw(FormattingException) -{ - if (longitude().getSIValue() != 0) { - std::string projPMName(getPROJStringWellKnownName(longitude())); - if (!projPMName.empty()) { - formatter->addParam("pm", projPMName); - } else { - const double valDeg = - longitude().convertToUnit(common::UnitOfMeasure::DEGREE); - formatter->addParam("pm", valDeg); - } - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool PrimeMeridian::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherPM = dynamic_cast<const PrimeMeridian *>(other); - if (otherPM == nullptr || - !IdentifiedObject::_isEquivalentTo(other, criterion)) { - return false; - } - // In MapInfo, the Paris prime meridian is returned as 2.3372291666667 - // instead of the official value of 2.33722917, which is a relative - // error in the 1e-9 range. - return longitude()._isEquivalentTo(otherPM->longitude(), criterion, 1e-8); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct Ellipsoid::Private { - common::Length semiMajorAxis_{}; - util::optional<common::Scale> inverseFlattening_{}; - util::optional<common::Length> semiMinorAxis_{}; - util::optional<common::Length> semiMedianAxis_{}; - std::string celestialBody_{}; - - explicit Private(const common::Length &radius, - const std::string &celestialBody) - : semiMajorAxis_(radius), celestialBody_(celestialBody) {} - - Private(const common::Length &semiMajorAxisIn, - const common::Scale &invFlattening, - const std::string &celestialBody) - : semiMajorAxis_(semiMajorAxisIn), inverseFlattening_(invFlattening), - celestialBody_(celestialBody) {} - - Private(const common::Length &semiMajorAxisIn, - const common::Length &semiMinorAxisIn, - const std::string &celestialBody) - : semiMajorAxis_(semiMajorAxisIn), semiMinorAxis_(semiMinorAxisIn), - celestialBody_(celestialBody) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -Ellipsoid::Ellipsoid(const common::Length &radius, - const std::string &celestialBodyIn) - : d(internal::make_unique<Private>(radius, celestialBodyIn)) {} - -// --------------------------------------------------------------------------- - -Ellipsoid::Ellipsoid(const common::Length &semiMajorAxisIn, - const common::Scale &invFlattening, - const std::string &celestialBodyIn) - : d(internal::make_unique<Private>(semiMajorAxisIn, invFlattening, - celestialBodyIn)) {} - -// --------------------------------------------------------------------------- - -Ellipsoid::Ellipsoid(const common::Length &semiMajorAxisIn, - const common::Length &semiMinorAxisIn, - const std::string &celestialBodyIn) - : d(internal::make_unique<Private>(semiMajorAxisIn, semiMinorAxisIn, - celestialBodyIn)) {} - -// --------------------------------------------------------------------------- - -#ifdef notdef -Ellipsoid::Ellipsoid(const Ellipsoid &other) - : common::IdentifiedObject(other), - d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -Ellipsoid::~Ellipsoid() = default; - -Ellipsoid::Ellipsoid(const Ellipsoid &other) - : IdentifiedObject(other), d(internal::make_unique<Private>(*(other.d))) {} - -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the length of the semi-major axis of the ellipsoid. - * - * @return the semi-major axis. - */ -const common::Length &Ellipsoid::semiMajorAxis() PROJ_CONST_DEFN { - return d->semiMajorAxis_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the inverse flattening value of the ellipsoid, if the - * ellipsoid - * has been defined with this value. - * - * @see computeInverseFlattening() that will always return a valid value of the - * inverse flattening, whether the ellipsoid has been defined through inverse - * flattening or semi-minor axis. - * - * @return the inverse flattening value of the ellipsoid, or empty. - */ -const util::optional<common::Scale> & -Ellipsoid::inverseFlattening() PROJ_CONST_DEFN { - return d->inverseFlattening_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the length of the semi-minor axis of the ellipsoid, if the - * ellipsoid - * has been defined with this value. - * - * @see computeSemiMinorAxis() that will always return a valid value of the - * inverse flattening, whether the ellipsoid has been defined through inverse - * flattening or semi-minor axis. - * - * @return the semi-minor axis of the ellipsoid, or empty. - */ -const util::optional<common::Length> & -Ellipsoid::semiMinorAxis() PROJ_CONST_DEFN { - return d->semiMinorAxis_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return whether the ellipsoid is spherical. - * - * That is to say is semiMajorAxis() == computeSemiMinorAxis(). - * - * A sphere is completely defined by the semi-major axis, which is the radius - * of the sphere. - * - * @return true if the ellipsoid is spherical. - */ -bool Ellipsoid::isSphere() PROJ_CONST_DEFN { - if (d->inverseFlattening_.has_value()) { - return d->inverseFlattening_->value() == 0; - } - - if (semiMinorAxis().has_value()) { - return semiMajorAxis() == *semiMinorAxis(); - } - - return true; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the length of the semi-median axis of a triaxial ellipsoid - * - * This parameter is not required for a biaxial ellipsoid. - * - * @return the semi-median axis of the ellipsoid, or empty. - */ -const util::optional<common::Length> & -Ellipsoid::semiMedianAxis() PROJ_CONST_DEFN { - return d->semiMedianAxis_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return or compute the inverse flattening value of the ellipsoid. - * - * If computed, the inverse flattening is the result of a / (a - b), - * where a is the semi-major axis and b the semi-minor axis. - * - * @return the inverse flattening value of the ellipsoid, or 0 for a sphere. - */ -double Ellipsoid::computedInverseFlattening() PROJ_CONST_DEFN { - if (d->inverseFlattening_.has_value()) { - return d->inverseFlattening_->getSIValue(); - } - - if (d->semiMinorAxis_.has_value()) { - const double a = d->semiMajorAxis_.getSIValue(); - const double b = d->semiMinorAxis_->getSIValue(); - return (a == b) ? 0.0 : a / (a - b); - } - - return 0.0; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the squared eccentricity of the ellipsoid. - * - * @return the squared eccentricity, or a negative value if invalid. - */ -double Ellipsoid::squaredEccentricity() PROJ_CONST_DEFN { - const double rf = computedInverseFlattening(); - const double f = rf != 0.0 ? 1. / rf : 0.0; - const double e2 = f * (2 - f); - return e2; -} - -// --------------------------------------------------------------------------- - -/** \brief Return or compute the length of the semi-minor axis of the ellipsoid. - * - * If computed, the semi-minor axis is the result of a * (1 - 1 / rf) - * where a is the semi-major axis and rf the reverse/inverse flattening. - - * @return the semi-minor axis of the ellipsoid. - */ -common::Length Ellipsoid::computeSemiMinorAxis() const { - if (d->semiMinorAxis_.has_value()) { - return *d->semiMinorAxis_; - } - - if (inverseFlattening().has_value()) { - return common::Length( - (1.0 - 1.0 / d->inverseFlattening_->getSIValue()) * - d->semiMajorAxis_.value(), - d->semiMajorAxis_.unit()); - } - - return d->semiMajorAxis_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the name of the celestial body on which the ellipsoid refers - * to. - */ -const std::string &Ellipsoid::celestialBody() PROJ_CONST_DEFN { - return d->celestialBody_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Ellipsoid as a sphere. - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param radius the sphere radius (semi-major axis). - * @param celestialBody Name of the celestial body on which the ellipsoid refers - * to. - * @return new Ellipsoid. - */ -EllipsoidNNPtr Ellipsoid::createSphere(const util::PropertyMap &properties, - const common::Length &radius, - const std::string &celestialBody) { - auto ellipsoid(Ellipsoid::nn_make_shared<Ellipsoid>(radius, celestialBody)); - ellipsoid->setProperties(properties); - return ellipsoid; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Ellipsoid from its inverse/reverse flattening. - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param semiMajorAxisIn the semi-major axis. - * @param invFlattening the inverse/reverse flattening. - * @param celestialBody Name of the celestial body on which the ellipsoid refers - * to. - * @return new Ellipsoid. - */ -EllipsoidNNPtr Ellipsoid::createFlattenedSphere( - const util::PropertyMap &properties, const common::Length &semiMajorAxisIn, - const common::Scale &invFlattening, const std::string &celestialBody) { - auto ellipsoid(Ellipsoid::nn_make_shared<Ellipsoid>( - semiMajorAxisIn, invFlattening, celestialBody)); - ellipsoid->setProperties(properties); - return ellipsoid; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Ellipsoid from the value of its two semi axis. - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param semiMajorAxisIn the semi-major axis. - * @param semiMinorAxisIn the semi-minor axis. - * @param celestialBody Name of the celestial body on which the ellipsoid refers - * to. - * @return new Ellipsoid. - */ -EllipsoidNNPtr Ellipsoid::createTwoAxis(const util::PropertyMap &properties, - const common::Length &semiMajorAxisIn, - const common::Length &semiMinorAxisIn, - const std::string &celestialBody) { - auto ellipsoid(Ellipsoid::nn_make_shared<Ellipsoid>( - semiMajorAxisIn, semiMinorAxisIn, celestialBody)); - ellipsoid->setProperties(properties); - return ellipsoid; -} - -// --------------------------------------------------------------------------- - -const EllipsoidNNPtr Ellipsoid::createCLARKE_1866() { - return createTwoAxis(createMapNameEPSGCode("Clarke 1866", 7008), - common::Length(6378206.4), common::Length(6356583.8)); -} - -// --------------------------------------------------------------------------- - -const EllipsoidNNPtr Ellipsoid::createWGS84() { - return createFlattenedSphere(createMapNameEPSGCode("WGS 84", 7030), - common::Length(6378137), - common::Scale(298.257223563)); -} - -// --------------------------------------------------------------------------- - -const EllipsoidNNPtr Ellipsoid::createGRS1980() { - return createFlattenedSphere(createMapNameEPSGCode("GRS 1980", 7019), - common::Length(6378137), - common::Scale(298.257222101)); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void Ellipsoid::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - formatter->startNode(isWKT2 ? io::WKTConstants::ELLIPSOID - : io::WKTConstants::SPHEROID, - !identifiers().empty()); - { - auto l_name = nameStr(); - if (l_name.empty()) { - formatter->addQuotedString("unnamed"); - } else { - if (formatter->useESRIDialect()) { - if (l_name == "WGS 84") { - l_name = "WGS_1984"; - } else { - bool aliasFound = false; - const auto &dbContext = formatter->databaseContext(); - if (dbContext) { - auto l_alias = dbContext->getAliasFromOfficialName( - l_name, "ellipsoid", "ESRI"); - if (!l_alias.empty()) { - l_name = l_alias; - aliasFound = true; - } - } - if (!aliasFound) { - l_name = io::WKTFormatter::morphNameToESRI(l_name); - } - } - } - formatter->addQuotedString(l_name); - } - const auto &semiMajor = semiMajorAxis(); - if (isWKT2) { - formatter->add(semiMajor.value()); - } else { - formatter->add(semiMajor.getSIValue()); - } - formatter->add(computedInverseFlattening()); - const auto &unit = semiMajor.unit(); - if (isWKT2 && - !(formatter->ellipsoidUnitOmittedIfMetre() && - unit == common::UnitOfMeasure::METRE)) { - unit._exportToWKT(formatter, io::WKTConstants::LENGTHUNIT); - } - if (formatter->outputId()) { - formatID(formatter); - } - } - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -bool Ellipsoid::lookForProjWellKnownEllps(std::string &projEllpsName, - std::string &ellpsName) const { - const double a = semiMajorAxis().getSIValue(); - const double b = computeSemiMinorAxis().getSIValue(); - const double rf = computedInverseFlattening(); - auto proj_ellps = proj_list_ellps(); - for (int i = 0; proj_ellps[i].id != nullptr; i++) { - assert(strncmp(proj_ellps[i].major, "a=", 2) == 0); - const double a_iter = c_locale_stod(proj_ellps[i].major + 2); - if (::fabs(a - a_iter) < 1e-10 * a_iter) { - if (strncmp(proj_ellps[i].ell, "b=", 2) == 0) { - const double b_iter = c_locale_stod(proj_ellps[i].ell + 2); - if (::fabs(b - b_iter) < 1e-10 * b_iter) { - projEllpsName = proj_ellps[i].id; - ellpsName = proj_ellps[i].name; - if (ellpsName.find("GRS 1980") == 0) { - ellpsName = "GRS 1980"; - } - return true; - } - } else { - assert(strncmp(proj_ellps[i].ell, "rf=", 3) == 0); - const double rf_iter = c_locale_stod(proj_ellps[i].ell + 3); - if (::fabs(rf - rf_iter) < 1e-10 * rf_iter) { - projEllpsName = proj_ellps[i].id; - ellpsName = proj_ellps[i].name; - if (ellpsName.find("GRS 1980") == 0) { - ellpsName = "GRS 1980"; - } - return true; - } - } - } - } - return false; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void Ellipsoid::_exportToPROJString( - io::PROJStringFormatter *formatter) const // throw(FormattingException) -{ - const double a = semiMajorAxis().getSIValue(); - - std::string projEllpsName; - std::string ellpsName; - if (lookForProjWellKnownEllps(projEllpsName, ellpsName)) { - formatter->addParam("ellps", projEllpsName); - return; - } - - if (isSphere()) { - formatter->addParam("R", a); - } else { - formatter->addParam("a", a); - if (inverseFlattening().has_value()) { - const double rf = computedInverseFlattening(); - formatter->addParam("rf", rf); - } else { - const double b = computeSemiMinorAxis().getSIValue(); - formatter->addParam("b", b); - } - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return a Ellipsoid object where some parameters are better - * identified. - * - * @return a new Ellipsoid. - */ -EllipsoidNNPtr Ellipsoid::identify() const { - auto newEllipsoid = Ellipsoid::nn_make_shared<Ellipsoid>(*this); - newEllipsoid->assignSelf( - util::nn_static_pointer_cast<util::BaseObject>(newEllipsoid)); - - if (name()->description()->empty() || nameStr() == "unknown") { - std::string projEllpsName; - std::string ellpsName; - if (lookForProjWellKnownEllps(projEllpsName, ellpsName)) { - newEllipsoid->setProperties( - util::PropertyMap().set(IdentifiedObject::NAME_KEY, ellpsName)); - } - } - - return newEllipsoid; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool Ellipsoid::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherEllipsoid = dynamic_cast<const Ellipsoid *>(other); - if (otherEllipsoid == nullptr || - (criterion == util::IComparable::Criterion::STRICT && - !IdentifiedObject::_isEquivalentTo(other, criterion))) { - return false; - } - - // PROJ "clrk80" name is "Clarke 1880 mod." and GDAL tends to - // export to it a number of Clarke 1880 variants, so be lax - if (criterion != util::IComparable::Criterion::STRICT && - (nameStr() == "Clarke 1880 mod." || - otherEllipsoid->nameStr() == "Clarke 1880 mod.")) { - return std::fabs(semiMajorAxis().getSIValue() - - otherEllipsoid->semiMajorAxis().getSIValue()) < - 1e-8 * semiMajorAxis().getSIValue() && - std::fabs(computedInverseFlattening() - - otherEllipsoid->computedInverseFlattening()) < - 1e-5 * computedInverseFlattening(); - } - - if (!semiMajorAxis()._isEquivalentTo(otherEllipsoid->semiMajorAxis(), - criterion)) { - return false; - } - - const auto &l_semiMinorAxis = semiMinorAxis(); - const auto &l_other_semiMinorAxis = otherEllipsoid->semiMinorAxis(); - if (l_semiMinorAxis.has_value() && l_other_semiMinorAxis.has_value()) { - if (!l_semiMinorAxis->_isEquivalentTo(*l_other_semiMinorAxis, - criterion)) { - return false; - } - } - - const auto &l_inverseFlattening = inverseFlattening(); - const auto &l_other_sinverseFlattening = - otherEllipsoid->inverseFlattening(); - if (l_inverseFlattening.has_value() && - l_other_sinverseFlattening.has_value()) { - if (!l_inverseFlattening->_isEquivalentTo(*l_other_sinverseFlattening, - criterion)) { - return false; - } - } - - if (criterion == util::IComparable::Criterion::STRICT) { - if ((l_semiMinorAxis.has_value() ^ l_other_semiMinorAxis.has_value())) { - return false; - } - - if ((l_inverseFlattening.has_value() ^ - l_other_sinverseFlattening.has_value())) { - return false; - } - - } else { - if (!otherEllipsoid->computeSemiMinorAxis()._isEquivalentTo( - otherEllipsoid->computeSemiMinorAxis(), criterion)) { - return false; - } - } - - const auto &l_semiMedianAxis = semiMedianAxis(); - const auto &l_other_semiMedianAxis = otherEllipsoid->semiMedianAxis(); - if ((l_semiMedianAxis.has_value() ^ l_other_semiMedianAxis.has_value())) { - return false; - } - if (l_semiMedianAxis.has_value() && l_other_semiMedianAxis.has_value()) { - if (!l_semiMedianAxis->_isEquivalentTo(*l_other_semiMedianAxis, - criterion)) { - return false; - } - } - return true; -} -//! @endcond - -// --------------------------------------------------------------------------- - -std::string Ellipsoid::guessBodyName(const io::DatabaseContextPtr &dbContext, - double a) { - constexpr double relError = 0.005; - constexpr double earthMeanRadius = 6375000.0; - if (std::fabs(a - earthMeanRadius) < relError * earthMeanRadius) { - return Ellipsoid::EARTH; - } - if (dbContext) { - try { - auto factory = io::AuthorityFactory::create(NN_NO_CHECK(dbContext), - std::string()); - return factory->identifyBodyFromSemiMajorAxis(a, relError); - } catch (const std::exception &) { - } - } - return "Non-Earth body"; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct GeodeticReferenceFrame::Private { - PrimeMeridianNNPtr primeMeridian_; - EllipsoidNNPtr ellipsoid_; - - Private(const EllipsoidNNPtr &ellipsoidIn, - const PrimeMeridianNNPtr &primeMeridianIn) - : primeMeridian_(primeMeridianIn), ellipsoid_(ellipsoidIn) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -GeodeticReferenceFrame::GeodeticReferenceFrame( - const EllipsoidNNPtr &ellipsoidIn, - const PrimeMeridianNNPtr &primeMeridianIn) - : d(internal::make_unique<Private>(ellipsoidIn, primeMeridianIn)) {} - -// --------------------------------------------------------------------------- - -#ifdef notdef -GeodeticReferenceFrame::GeodeticReferenceFrame( - const GeodeticReferenceFrame &other) - : Datum(other), d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -GeodeticReferenceFrame::~GeodeticReferenceFrame() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the PrimeMeridian associated with a GeodeticReferenceFrame. - * - * @return the PrimeMeridian. - */ -const PrimeMeridianNNPtr & -GeodeticReferenceFrame::primeMeridian() PROJ_CONST_DEFN { - return d->primeMeridian_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the Ellipsoid associated with a GeodeticReferenceFrame. - * - * \note The \ref ISO_19111_2018 modelling allows (but discourages) a - * GeodeticReferenceFrame - * to not be associated with a Ellipsoid in the case where it is used by a - * geocentric crs::GeodeticCRS. We have made the choice of making the ellipsoid - * specification compulsory. - * - * @return the Ellipsoid. - */ -const EllipsoidNNPtr &GeodeticReferenceFrame::ellipsoid() PROJ_CONST_DEFN { - return d->ellipsoid_; -} -// --------------------------------------------------------------------------- - -/** \brief Instanciate a GeodeticReferenceFrame - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param ellipsoid the Ellipsoid. - * @param anchor the anchor definition, or empty. - * @param primeMeridian the PrimeMeridian. - * @return new GeodeticReferenceFrame. - */ -GeodeticReferenceFrameNNPtr -GeodeticReferenceFrame::create(const util::PropertyMap &properties, - const EllipsoidNNPtr &ellipsoid, - const util::optional<std::string> &anchor, - const PrimeMeridianNNPtr &primeMeridian) { - GeodeticReferenceFrameNNPtr grf( - GeodeticReferenceFrame::nn_make_shared<GeodeticReferenceFrame>( - ellipsoid, primeMeridian)); - grf->setAnchor(anchor); - grf->setProperties(properties); - return grf; -} - -// --------------------------------------------------------------------------- - -const GeodeticReferenceFrameNNPtr GeodeticReferenceFrame::createEPSG_6267() { - return create(createMapNameEPSGCode("North American Datum 1927", 6267), - Ellipsoid::CLARKE_1866, util::optional<std::string>(), - PrimeMeridian::GREENWICH); -} - -// --------------------------------------------------------------------------- - -const GeodeticReferenceFrameNNPtr GeodeticReferenceFrame::createEPSG_6269() { - return create(createMapNameEPSGCode("North American Datum 1983", 6269), - Ellipsoid::GRS1980, util::optional<std::string>(), - PrimeMeridian::GREENWICH); -} - -// --------------------------------------------------------------------------- - -const GeodeticReferenceFrameNNPtr GeodeticReferenceFrame::createEPSG_6326() { - return create(createMapNameEPSGCode("World Geodetic System 1984", 6326), - Ellipsoid::WGS84, util::optional<std::string>(), - PrimeMeridian::GREENWICH); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void GeodeticReferenceFrame::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - formatter->startNode(io::WKTConstants::DATUM, !identifiers().empty()); - auto l_name = nameStr(); - if (l_name.empty()) { - l_name = "unnamed"; - } - if (!isWKT2) { - if (formatter->useESRIDialect()) { - if (l_name == "World Geodetic System 1984") { - l_name = "D_WGS_1984"; - } else { - bool aliasFound = false; - const auto &dbContext = formatter->databaseContext(); - if (dbContext) { - auto l_alias = dbContext->getAliasFromOfficialName( - l_name, "geodetic_datum", "ESRI"); - size_t pos; - if (!l_alias.empty()) { - l_name = l_alias; - aliasFound = true; - } else if ((pos = l_name.find(" (")) != std::string::npos) { - l_alias = dbContext->getAliasFromOfficialName( - l_name.substr(0, pos), "geodetic_datum", "ESRI"); - if (!l_alias.empty()) { - l_name = l_alias; - aliasFound = true; - } - } - } - if (!aliasFound) { - l_name = io::WKTFormatter::morphNameToESRI(l_name); - if (!starts_with(l_name, "D_")) { - l_name = "D_" + l_name; - } - } - } - // Replace spaces by underscore, except if it is a special MapInfo - // datum name - } else if (!starts_with(l_name, "MIF ")) { - l_name = io::WKTFormatter::morphNameToESRI(l_name); - if (l_name == "World_Geodetic_System_1984") { - l_name = "WGS_1984"; - } - } - } - formatter->addQuotedString(l_name); - - ellipsoid()->_exportToWKT(formatter); - if (isWKT2) { - Datum::getPrivate()->exportAnchorDefinition(formatter); - } else { - const auto &TOWGS84Params = formatter->getTOWGS84Parameters(); - if (TOWGS84Params.size() == 7) { - formatter->startNode(io::WKTConstants::TOWGS84, false); - for (const auto &val : TOWGS84Params) { - formatter->add(val); - } - formatter->endNode(); - } - std::string extension = formatter->getHDatumExtension(); - if (!extension.empty()) { - formatter->startNode(io::WKTConstants::EXTENSION, false); - formatter->addQuotedString("PROJ4_GRIDS"); - formatter->addQuotedString(extension); - formatter->endNode(); - } - } - if (formatter->outputId()) { - formatID(formatter); - } - // the PRIMEM is exported as a child of the CRS - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool GeodeticReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherGRF = dynamic_cast<const GeodeticReferenceFrame *>(other); - if (otherGRF == nullptr || !Datum::_isEquivalentTo(other, criterion)) { - return false; - } - return primeMeridian()->_isEquivalentTo(otherGRF->primeMeridian().get(), - criterion) && - ellipsoid()->_isEquivalentTo(otherGRF->ellipsoid().get(), criterion); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct DynamicGeodeticReferenceFrame::Private { - common::Measure frameReferenceEpoch{}; - util::optional<std::string> deformationModelName{}; - - explicit Private(const common::Measure &frameReferenceEpochIn) - : frameReferenceEpoch(frameReferenceEpochIn) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -DynamicGeodeticReferenceFrame::DynamicGeodeticReferenceFrame( - const EllipsoidNNPtr &ellipsoidIn, - const PrimeMeridianNNPtr &primeMeridianIn, - const common::Measure &frameReferenceEpochIn, - const util::optional<std::string> &deformationModelNameIn) - : GeodeticReferenceFrame(ellipsoidIn, primeMeridianIn), - d(internal::make_unique<Private>(frameReferenceEpochIn)) { - d->deformationModelName = deformationModelNameIn; -} - -// --------------------------------------------------------------------------- - -#ifdef notdef -DynamicGeodeticReferenceFrame::DynamicGeodeticReferenceFrame( - const DynamicGeodeticReferenceFrame &other) - : GeodeticReferenceFrame(other), - d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -DynamicGeodeticReferenceFrame::~DynamicGeodeticReferenceFrame() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the epoch to which the coordinates of stations defining the - * dynamic geodetic reference frame are referenced. - * - * Usually given as a decimal year e.g. 2016.47. - * - * @return the frame reference epoch. - */ -const common::Measure & -DynamicGeodeticReferenceFrame::frameReferenceEpoch() const { - return d->frameReferenceEpoch; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the name of the deformation model. - * - * @note This is an extension to the \ref ISO_19111_2018 modeling, to - * hold the content of the DYNAMIC.MODEL WKT2 node. - * - * @return the name of the deformation model. - */ -const util::optional<std::string> & -DynamicGeodeticReferenceFrame::deformationModelName() const { - return d->deformationModelName; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool DynamicGeodeticReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherDGRF = dynamic_cast<const DynamicGeodeticReferenceFrame *>(other); - if (otherDGRF == nullptr || - !GeodeticReferenceFrame::_isEquivalentTo(other, criterion)) { - return false; - } - return frameReferenceEpoch()._isEquivalentTo( - otherDGRF->frameReferenceEpoch(), criterion) && - metadata::Identifier::isEquivalentName( - deformationModelName()->c_str(), - otherDGRF->deformationModelName()->c_str()); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void DynamicGeodeticReferenceFrame::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - if (isWKT2 && formatter->use2018Keywords()) { - formatter->startNode(io::WKTConstants::DYNAMIC, false); - formatter->startNode(io::WKTConstants::FRAMEEPOCH, false); - formatter->add( - frameReferenceEpoch().convertToUnit(common::UnitOfMeasure::YEAR)); - formatter->endNode(); - if (deformationModelName().has_value() && - !deformationModelName()->empty()) { - formatter->startNode(io::WKTConstants::MODEL, false); - formatter->addQuotedString(*deformationModelName()); - formatter->endNode(); - } - formatter->endNode(); - } - GeodeticReferenceFrame::_exportToWKT(formatter); -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a DyanmicGeodeticReferenceFrame - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param ellipsoid the Ellipsoid. - * @param anchor the anchor definition, or empty. - * @param primeMeridian the PrimeMeridian. - * @param frameReferenceEpochIn the frame reference epoch. - * @param deformationModelNameIn deformation model name, or empty - * @return new DyanmicGeodeticReferenceFrame. - */ -DynamicGeodeticReferenceFrameNNPtr DynamicGeodeticReferenceFrame::create( - const util::PropertyMap &properties, const EllipsoidNNPtr &ellipsoid, - const util::optional<std::string> &anchor, - const PrimeMeridianNNPtr &primeMeridian, - const common::Measure &frameReferenceEpochIn, - const util::optional<std::string> &deformationModelNameIn) { - DynamicGeodeticReferenceFrameNNPtr grf( - DynamicGeodeticReferenceFrame::nn_make_shared< - DynamicGeodeticReferenceFrame>(ellipsoid, primeMeridian, - frameReferenceEpochIn, - deformationModelNameIn)); - grf->setAnchor(anchor); - grf->setProperties(properties); - return grf; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct DatumEnsemble::Private { - std::vector<DatumNNPtr> datums{}; - metadata::PositionalAccuracyNNPtr positionalAccuracy; - - Private(const std::vector<DatumNNPtr> &datumsIn, - const metadata::PositionalAccuracyNNPtr &accuracy) - : datums(datumsIn), positionalAccuracy(accuracy) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -DatumEnsemble::DatumEnsemble(const std::vector<DatumNNPtr> &datumsIn, - const metadata::PositionalAccuracyNNPtr &accuracy) - : d(internal::make_unique<Private>(datumsIn, accuracy)) {} - -// --------------------------------------------------------------------------- - -#ifdef notdef -DatumEnsemble::DatumEnsemble(const DatumEnsemble &other) - : common::IdentifiedObject(other), - d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -DatumEnsemble::~DatumEnsemble() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the set of datums which may be considered to be - * insignificantly different from each other. - * - * @return the set of datums of the DatumEnsemble. - */ -const std::vector<DatumNNPtr> &DatumEnsemble::datums() const { - return d->datums; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the inaccuracy introduced through use of this collection of - * datums. - * - * It is an indication of the differences in coordinate values at all points - * between the various realizations that have been grouped into this datum - * ensemble. - * - * @return the accuracy. - */ -const metadata::PositionalAccuracyNNPtr & -DatumEnsemble::positionalAccuracy() const { - return d->positionalAccuracy; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void DatumEnsemble::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - if (!isWKT2 || !formatter->use2018Keywords()) { - throw io::FormattingException( - "DatumEnsemble can only be exported to WKT2:2018"); - } - - auto l_datums = datums(); - assert(!l_datums.empty()); - - formatter->startNode(io::WKTConstants::ENSEMBLE, false); - const auto &l_name = nameStr(); - if (!l_name.empty()) { - formatter->addQuotedString(l_name); - } else { - formatter->addQuotedString("unnamed"); - } - - for (const auto &datum : l_datums) { - formatter->startNode(io::WKTConstants::MEMBER, - !datum->identifiers().empty()); - const auto &l_datum_name = datum->nameStr(); - if (!l_datum_name.empty()) { - formatter->addQuotedString(l_datum_name); - } else { - formatter->addQuotedString("unnamed"); - } - if (formatter->outputId()) { - datum->formatID(formatter); - } - formatter->endNode(); - } - - auto grfFirst = std::dynamic_pointer_cast<GeodeticReferenceFrame>( - l_datums[0].as_nullable()); - if (grfFirst) { - grfFirst->ellipsoid()->_exportToWKT(formatter); - } - - formatter->startNode(io::WKTConstants::ENSEMBLEACCURACY, false); - formatter->add(positionalAccuracy()->value()); - formatter->endNode(); - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a DatumEnsemble. - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param datumsIn Array of at least 2 datums. - * @param accuracy Accuracy of the datum ensemble - * @return new DatumEnsemble. - * @throw util::Exception - */ -DatumEnsembleNNPtr DatumEnsemble::create( - const util::PropertyMap &properties, - const std::vector<DatumNNPtr> &datumsIn, - const metadata::PositionalAccuracyNNPtr &accuracy) // throw(Exception) -{ - if (datumsIn.size() < 2) { - throw util::Exception("ensemble should have at least 2 datums"); - } - if (auto grfFirst = - dynamic_cast<const GeodeticReferenceFrame *>(datumsIn[0].get())) { - for (size_t i = 1; i < datumsIn.size(); i++) { - auto grf = - dynamic_cast<const GeodeticReferenceFrame *>(datumsIn[i].get()); - if (!grf) { - throw util::Exception( - "ensemble should have consistent datum types"); - } - if (!grfFirst->ellipsoid()->_isEquivalentTo( - grf->ellipsoid().get())) { - throw util::Exception( - "ensemble should have datums with identical ellipsoid"); - } - if (!grfFirst->primeMeridian()->_isEquivalentTo( - grf->primeMeridian().get())) { - throw util::Exception( - "ensemble should have datums with identical " - "prime meridian"); - } - } - } else if (dynamic_cast<VerticalReferenceFrame *>(datumsIn[0].get())) { - for (size_t i = 1; i < datumsIn.size(); i++) { - if (!dynamic_cast<VerticalReferenceFrame *>(datumsIn[i].get())) { - throw util::Exception( - "ensemble should have consistent datum types"); - } - } - } - auto ensemble( - DatumEnsemble::nn_make_shared<DatumEnsemble>(datumsIn, accuracy)); - ensemble->setProperties(properties); - return ensemble; -} - -// --------------------------------------------------------------------------- - -RealizationMethod::RealizationMethod(const std::string &nameIn) - : CodeList(nameIn) {} - -// --------------------------------------------------------------------------- - -RealizationMethod::RealizationMethod(const RealizationMethod &) = default; - -// --------------------------------------------------------------------------- - -RealizationMethod &RealizationMethod:: -operator=(const RealizationMethod &other) { - CodeList::operator=(other); - return *this; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct VerticalReferenceFrame::Private { - util::optional<RealizationMethod> realizationMethod_{}; -}; -//! @endcond - -// --------------------------------------------------------------------------- - -VerticalReferenceFrame::VerticalReferenceFrame( - const util::optional<RealizationMethod> &realizationMethodIn) - : d(internal::make_unique<Private>()) { - if (!realizationMethodIn->toString().empty()) { - d->realizationMethod_ = *realizationMethodIn; - } -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -VerticalReferenceFrame::~VerticalReferenceFrame() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the method through which this vertical reference frame is - * realized. - * - * @return the realization method. - */ -const util::optional<RealizationMethod> & -VerticalReferenceFrame::realizationMethod() const { - return d->realizationMethod_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a VerticalReferenceFrame - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param anchor the anchor definition, or empty. - * @param realizationMethodIn the realization method, or empty. - * @return new VerticalReferenceFrame. - */ -VerticalReferenceFrameNNPtr VerticalReferenceFrame::create( - const util::PropertyMap &properties, - const util::optional<std::string> &anchor, - const util::optional<RealizationMethod> &realizationMethodIn) { - auto rf(VerticalReferenceFrame::nn_make_shared<VerticalReferenceFrame>( - realizationMethodIn)); - rf->setAnchor(anchor); - rf->setProperties(properties); - return rf; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void VerticalReferenceFrame::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - formatter->startNode(isWKT2 ? io::WKTConstants::VDATUM - : io::WKTConstants::VERT_DATUM, - !identifiers().empty()); - const auto &l_name = nameStr(); - if (!l_name.empty()) { - formatter->addQuotedString(l_name); - } else { - formatter->addQuotedString("unnamed"); - } - if (isWKT2) { - Datum::getPrivate()->exportAnchorDefinition(formatter); - } else { - formatter->add(2005); // CS_VD_GeoidModelDerived from OGC 01-009 - const auto &extension = formatter->getVDatumExtension(); - if (!extension.empty()) { - formatter->startNode(io::WKTConstants::EXTENSION, false); - formatter->addQuotedString("PROJ4_GRIDS"); - formatter->addQuotedString(extension); - formatter->endNode(); - } - } - if (formatter->outputId()) { - formatID(formatter); - } - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool VerticalReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherVRF = dynamic_cast<const VerticalReferenceFrame *>(other); - if (otherVRF == nullptr || !Datum::_isEquivalentTo(other, criterion)) { - return false; - } - if ((realizationMethod().has_value() ^ - otherVRF->realizationMethod().has_value())) { - return false; - } - if (realizationMethod().has_value() && - otherVRF->realizationMethod().has_value()) { - if (*(realizationMethod()) != *(otherVRF->realizationMethod())) { - return false; - } - } - return true; -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct DynamicVerticalReferenceFrame::Private { - common::Measure frameReferenceEpoch{}; - util::optional<std::string> deformationModelName{}; - - explicit Private(const common::Measure &frameReferenceEpochIn) - : frameReferenceEpoch(frameReferenceEpochIn) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -DynamicVerticalReferenceFrame::DynamicVerticalReferenceFrame( - const util::optional<RealizationMethod> &realizationMethodIn, - const common::Measure &frameReferenceEpochIn, - const util::optional<std::string> &deformationModelNameIn) - : VerticalReferenceFrame(realizationMethodIn), - d(internal::make_unique<Private>(frameReferenceEpochIn)) { - d->deformationModelName = deformationModelNameIn; -} - -// --------------------------------------------------------------------------- - -#ifdef notdef -DynamicVerticalReferenceFrame::DynamicVerticalReferenceFrame( - const DynamicVerticalReferenceFrame &other) - : VerticalReferenceFrame(other), - d(internal::make_unique<Private>(*other.d)) {} -#endif - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -DynamicVerticalReferenceFrame::~DynamicVerticalReferenceFrame() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the epoch to which the coordinates of stations defining the - * dynamic geodetic reference frame are referenced. - * - * Usually given as a decimal year e.g. 2016.47. - * - * @return the frame reference epoch. - */ -const common::Measure & -DynamicVerticalReferenceFrame::frameReferenceEpoch() const { - return d->frameReferenceEpoch; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the name of the deformation model. - * - * @note This is an extension to the \ref ISO_19111_2018 modeling, to - * hold the content of the DYNAMIC.MODEL WKT2 node. - * - * @return the name of the deformation model. - */ -const util::optional<std::string> & -DynamicVerticalReferenceFrame::deformationModelName() const { - return d->deformationModelName; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool DynamicVerticalReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherDGRF = dynamic_cast<const DynamicVerticalReferenceFrame *>(other); - if (otherDGRF == nullptr || - !VerticalReferenceFrame::_isEquivalentTo(other, criterion)) { - return false; - } - return frameReferenceEpoch()._isEquivalentTo( - otherDGRF->frameReferenceEpoch(), criterion) && - metadata::Identifier::isEquivalentName( - deformationModelName()->c_str(), - otherDGRF->deformationModelName()->c_str()); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void DynamicVerticalReferenceFrame::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - if (isWKT2 && formatter->use2018Keywords()) { - formatter->startNode(io::WKTConstants::DYNAMIC, false); - formatter->startNode(io::WKTConstants::FRAMEEPOCH, false); - formatter->add( - frameReferenceEpoch().convertToUnit(common::UnitOfMeasure::YEAR)); - formatter->endNode(); - if (!deformationModelName()->empty()) { - formatter->startNode(io::WKTConstants::MODEL, false); - formatter->addQuotedString(*deformationModelName()); - formatter->endNode(); - } - formatter->endNode(); - } - VerticalReferenceFrame::_exportToWKT(formatter); -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a DyanmicVerticalReferenceFrame - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param anchor the anchor definition, or empty. - * @param realizationMethodIn the realization method, or empty. - * @param frameReferenceEpochIn the frame reference epoch. - * @param deformationModelNameIn deformation model name, or empty - * @return new DyanmicVerticalReferenceFrame. - */ -DynamicVerticalReferenceFrameNNPtr DynamicVerticalReferenceFrame::create( - const util::PropertyMap &properties, - const util::optional<std::string> &anchor, - const util::optional<RealizationMethod> &realizationMethodIn, - const common::Measure &frameReferenceEpochIn, - const util::optional<std::string> &deformationModelNameIn) { - DynamicVerticalReferenceFrameNNPtr grf( - DynamicVerticalReferenceFrame::nn_make_shared< - DynamicVerticalReferenceFrame>(realizationMethodIn, - frameReferenceEpochIn, - deformationModelNameIn)); - grf->setAnchor(anchor); - grf->setProperties(properties); - return grf; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct TemporalDatum::Private { - common::DateTime temporalOrigin_; - std::string calendar_; - - Private(const common::DateTime &temporalOriginIn, - const std::string &calendarIn) - : temporalOrigin_(temporalOriginIn), calendar_(calendarIn) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -TemporalDatum::TemporalDatum(const common::DateTime &temporalOriginIn, - const std::string &calendarIn) - : d(internal::make_unique<Private>(temporalOriginIn, calendarIn)) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -TemporalDatum::~TemporalDatum() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the date and time to which temporal coordinates are - * referenced, expressed in conformance with ISO 8601. - * - * @return the temporal origin. - */ -const common::DateTime &TemporalDatum::temporalOrigin() const { - return d->temporalOrigin_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the calendar to which the temporal origin is referenced - * - * Default value: TemporalDatum::CALENDAR_PROLEPTIC_GREGORIAN. - * - * @return the calendar. - */ -const std::string &TemporalDatum::calendar() const { return d->calendar_; } - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a TemporalDatum - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param temporalOriginIn the temporal origin into which temporal coordinates - * are referenced. - * @param calendarIn the calendar (generally - * TemporalDatum::CALENDAR_PROLEPTIC_GREGORIAN) - * @return new TemporalDatum. - */ -TemporalDatumNNPtr -TemporalDatum::create(const util::PropertyMap &properties, - const common::DateTime &temporalOriginIn, - const std::string &calendarIn) { - auto datum(TemporalDatum::nn_make_shared<TemporalDatum>(temporalOriginIn, - calendarIn)); - datum->setProperties(properties); - return datum; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void TemporalDatum::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - if (!isWKT2) { - throw io::FormattingException( - "TemporalDatum can only be exported to WKT2"); - } - formatter->startNode(io::WKTConstants::TDATUM, !identifiers().empty()); - formatter->addQuotedString(nameStr()); - if (formatter->use2018Keywords()) { - formatter->startNode(io::WKTConstants::CALENDAR, false); - formatter->addQuotedString(calendar()); - formatter->endNode(); - } - - const auto &timeOriginStr = temporalOrigin().toString(); - if (!timeOriginStr.empty()) { - formatter->startNode(io::WKTConstants::TIMEORIGIN, false); - if (temporalOrigin().isISO_8601()) { - formatter->add(timeOriginStr); - } else { - formatter->addQuotedString(timeOriginStr); - } - formatter->endNode(); - } - - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool TemporalDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherTD = dynamic_cast<const TemporalDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { - return false; - } - return temporalOrigin().toString() == - otherTD->temporalOrigin().toString() && - calendar() == otherTD->calendar(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct EngineeringDatum::Private {}; -//! @endcond - -// --------------------------------------------------------------------------- - -EngineeringDatum::EngineeringDatum() : d(nullptr) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -EngineeringDatum::~EngineeringDatum() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a EngineeringDatum - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param anchor the anchor definition, or empty. - * @return new EngineeringDatum. - */ -EngineeringDatumNNPtr -EngineeringDatum::create(const util::PropertyMap &properties, - const util::optional<std::string> &anchor) { - auto datum(EngineeringDatum::nn_make_shared<EngineeringDatum>()); - datum->setAnchor(anchor); - datum->setProperties(properties); - return datum; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void EngineeringDatum::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - formatter->startNode(isWKT2 ? io::WKTConstants::EDATUM - : io::WKTConstants::LOCAL_DATUM, - !identifiers().empty()); - formatter->addQuotedString(nameStr()); - if (isWKT2) { - Datum::getPrivate()->exportAnchorDefinition(formatter); - } else { - // Somewhat picked up arbitrarily from OGC 01-009: - // CS_LD_Max (Attribute) : 32767 - // Highest possible value for local datum types. - formatter->add(32767); - } - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool EngineeringDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherTD = dynamic_cast<const EngineeringDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { - return false; - } - return true; -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct ParametricDatum::Private {}; -//! @endcond - -// --------------------------------------------------------------------------- - -ParametricDatum::ParametricDatum() : d(nullptr) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -ParametricDatum::~ParametricDatum() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a ParametricDatum - * - * @param properties See \ref general_properties. - * At minimum the name should be defined. - * @param anchor the anchor definition, or empty. - * @return new ParametricDatum. - */ -ParametricDatumNNPtr -ParametricDatum::create(const util::PropertyMap &properties, - const util::optional<std::string> &anchor) { - auto datum(ParametricDatum::nn_make_shared<ParametricDatum>()); - datum->setAnchor(anchor); - datum->setProperties(properties); - return datum; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void ParametricDatum::_exportToWKT( - io::WKTFormatter *formatter) const // throw(FormattingException) -{ - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - if (!isWKT2) { - throw io::FormattingException( - "ParametricDatum can only be exported to WKT2"); - } - formatter->startNode(io::WKTConstants::PDATUM, !identifiers().empty()); - formatter->addQuotedString(nameStr()); - Datum::getPrivate()->exportAnchorDefinition(formatter); - formatter->endNode(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool ParametricDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherTD = dynamic_cast<const ParametricDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { - return false; - } - return true; -} -//! @endcond - -} // namespace datum -NS_PROJ_END |
