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/metadata.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/metadata.cpp')
| -rw-r--r-- | src/metadata.cpp | 1285 |
1 files changed, 0 insertions, 1285 deletions
diff --git a/src/metadata.cpp b/src/metadata.cpp deleted file mode 100644 index 2be9dac3..00000000 --- a/src/metadata.cpp +++ /dev/null @@ -1,1285 +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/metadata.hpp" -#include "proj/common.hpp" -#include "proj/io.hpp" -#include "proj/util.hpp" - -#include "proj/internal/internal.hpp" -#include "proj/internal/io_internal.hpp" - -#include <algorithm> -#include <memory> -#include <string> -#include <vector> - -using namespace NS_PROJ::internal; -using namespace NS_PROJ::io; -using namespace NS_PROJ::util; - -#if 0 -namespace dropbox{ namespace oxygen { -template<> nn<std::shared_ptr<NS_PROJ::metadata::Citation>>::~nn() = default; -template<> nn<NS_PROJ::metadata::ExtentPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::GeographicBoundingBoxPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::GeographicExtentPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::VerticalExtentPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::TemporalExtentPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::IdentifierPtr>::~nn() = default; -template<> nn<NS_PROJ::metadata::PositionalAccuracyPtr>::~nn() = default; -}} -#endif - -NS_PROJ_START -namespace metadata { - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct Citation::Private { - optional<std::string> title{}; -}; -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -Citation::Citation() : d(internal::make_unique<Private>()) {} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Constructs a citation by its title. */ -Citation::Citation(const std::string &titleIn) - : d(internal::make_unique<Private>()) { - d->title = titleIn; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -Citation::Citation(const Citation &other) - : d(internal::make_unique<Private>(*(other.d))) {} - -// --------------------------------------------------------------------------- - -Citation::~Citation() = default; - -// --------------------------------------------------------------------------- - -Citation &Citation::operator=(const Citation &other) { - if (this != &other) { - *d = *other.d; - } - return *this; -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns the name by which the cited resource is known. */ -const optional<std::string> &Citation::title() PROJ_CONST_DEFN { - return d->title; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct GeographicExtent::Private {}; -//! @endcond - -// --------------------------------------------------------------------------- - -GeographicExtent::GeographicExtent() : d(internal::make_unique<Private>()) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -GeographicExtent::~GeographicExtent() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct GeographicBoundingBox::Private { - double west_{}; - double south_{}; - double east_{}; - double north_{}; - - Private(double west, double south, double east, double north) - : west_(west), south_(south), east_(east), north_(north) {} - - bool intersects(const Private &other) const; - - std::unique_ptr<Private> intersection(const Private &other) const; -}; -//! @endcond - -// --------------------------------------------------------------------------- - -GeographicBoundingBox::GeographicBoundingBox(double west, double south, - double east, double north) - : GeographicExtent(), - d(internal::make_unique<Private>(west, south, east, north)) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -GeographicBoundingBox::~GeographicBoundingBox() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns the western-most coordinate of the limit of the dataset - * extent. - * - * The unit is degrees. - * - * If eastBoundLongitude < westBoundLongitude(), then the bounding box crosses - * the anti-meridian. - */ -double GeographicBoundingBox::westBoundLongitude() PROJ_CONST_DEFN { - return d->west_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the southern-most coordinate of the limit of the dataset - * extent. - * - * The unit is degrees. - */ -double GeographicBoundingBox::southBoundLatitude() PROJ_CONST_DEFN { - return d->south_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the eastern-most coordinate of the limit of the dataset - * extent. - * - * The unit is degrees. - * - * If eastBoundLongitude < westBoundLongitude(), then the bounding box crosses - * the anti-meridian. - */ -double GeographicBoundingBox::eastBoundLongitude() PROJ_CONST_DEFN { - return d->east_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the northern-most coordinate of the limit of the dataset - * extent. - * - * The unit is degrees. - */ -double GeographicBoundingBox::northBoundLatitude() PROJ_CONST_DEFN { - return d->north_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a GeographicBoundingBox. - * - * If east < west, then the bounding box crosses the anti-meridian. - * - * @param west Western-most coordinate of the limit of the dataset extent (in - * degrees). - * @param south Southern-most coordinate of the limit of the dataset extent (in - * degrees). - * @param east Eastern-most coordinate of the limit of the dataset extent (in - * degrees). - * @param north Northern-most coordinate of the limit of the dataset extent (in - * degrees). - * @return a new GeographicBoundingBox. - */ -GeographicBoundingBoxNNPtr GeographicBoundingBox::create(double west, - double south, - double east, - double north) { - return GeographicBoundingBox::nn_make_shared<GeographicBoundingBox>( - west, south, east, north); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool GeographicBoundingBox::_isEquivalentTo( - const util::IComparable *other, util::IComparable::Criterion) const { - auto otherExtent = dynamic_cast<const GeographicBoundingBox *>(other); - if (!otherExtent) - return false; - return d->west_ == otherExtent->d->west_ && - d->south_ == otherExtent->d->south_ && - d->east_ == otherExtent->d->east_ && - d->north_ == otherExtent->d->north_; -} -//! @endcond - -// --------------------------------------------------------------------------- - -bool GeographicBoundingBox::contains(const GeographicExtentNNPtr &other) const { - auto otherExtent = dynamic_cast<const GeographicBoundingBox *>(other.get()); - if (!otherExtent) { - return false; - } - const double W = d->west_; - const double E = d->east_; - const double N = d->north_; - const double S = d->south_; - const double oW = otherExtent->d->west_; - const double oE = otherExtent->d->east_; - const double oN = otherExtent->d->north_; - const double oS = otherExtent->d->south_; - - if (!(S <= oS && N >= oN)) { - return false; - } - - if (W == -180.0 && E == 180.0) { - return true; - } - - if (oW == -180.0 && oE == 180.0) { - return false; - } - - // Normal bounding box ? - if (W < E) { - if (oW < oE) { - return W <= oW && E >= oE; - } else { - return false; - } - // No: crossing antimerian - } else { - if (oW < oE) { - if (oW >= W) { - return true; - } else if (oE <= E) { - return true; - } else { - return false; - } - } else { - return W <= oW && E >= oE; - } - } -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool GeographicBoundingBox::Private::intersects(const Private &other) const { - const double W = west_; - const double E = east_; - const double N = north_; - const double S = south_; - const double oW = other.west_; - const double oE = other.east_; - const double oN = other.north_; - const double oS = other.south_; - - if (N < oS || S > oN) { - return false; - } - - if (W == -180.0 && E == 180.0 && oW > oE) { - return true; - } - - if (oW == -180.0 && oE == 180.0 && W > E) { - return true; - } - - // Normal bounding box ? - if (W <= E) { - if (oW < oE) { - if (std::max(W, oW) < std::min(E, oE)) { - return true; - } - return false; - } - - return intersects(Private(oW, oS, 180.0, oN)) || - intersects(Private(-180.0, oS, oE, oN)); - - // No: crossing antimerian - } else { - if (oW <= oE) { - return other.intersects(*this); - } - - return true; - } -} -//! @endcond - -bool GeographicBoundingBox::intersects( - const GeographicExtentNNPtr &other) const { - auto otherExtent = dynamic_cast<const GeographicBoundingBox *>(other.get()); - if (!otherExtent) { - return false; - } - return d->intersects(*(otherExtent->d)); -} - -// --------------------------------------------------------------------------- - -GeographicExtentPtr -GeographicBoundingBox::intersection(const GeographicExtentNNPtr &other) const { - auto otherExtent = dynamic_cast<const GeographicBoundingBox *>(other.get()); - if (!otherExtent) { - return nullptr; - } - auto ret = d->intersection(*(otherExtent->d)); - if (ret) { - auto bbox = GeographicBoundingBox::create(ret->west_, ret->south_, - ret->east_, ret->north_); - return bbox.as_nullable(); - } - return nullptr; -} - -//! @cond Doxygen_Suppress -std::unique_ptr<GeographicBoundingBox::Private> -GeographicBoundingBox::Private::intersection(const Private &otherExtent) const { - const double W = west_; - const double E = east_; - const double N = north_; - const double S = south_; - const double oW = otherExtent.west_; - const double oE = otherExtent.east_; - const double oN = otherExtent.north_; - const double oS = otherExtent.south_; - - if (N < oS || S > oN) { - return nullptr; - } - - if (W == -180.0 && E == 180.0 && oW > oE) { - return internal::make_unique<Private>(oW, std::max(S, oS), oE, - std::min(N, oN)); - } - - if (oW == -180.0 && oE == 180.0 && W > E) { - return internal::make_unique<Private>(W, std::max(S, oS), E, - std::min(N, oN)); - } - - // Normal bounding box ? - if (W <= E) { - if (oW < oE) { - auto res = internal::make_unique<Private>( - std::max(W, oW), std::max(S, oS), std::min(E, oE), - std::min(N, oN)); - if (res->west_ < res->east_) { - return res; - } - return nullptr; - } - - // Return larger of two parts of the multipolygon - auto inter1 = intersection(Private(oW, oS, 180.0, oN)); - auto inter2 = intersection(Private(-180.0, oS, oE, oN)); - if (!inter1) { - return inter2; - } - if (!inter2) { - return inter1; - } - if (inter1->east_ - inter1->west_ > inter2->east_ - inter2->west_) { - return inter1; - } - return inter2; - // No: crossing antimerian - } else { - if (oW <= oE) { - return otherExtent.intersection(*this); - } - - return internal::make_unique<Private>(std::max(W, oW), std::max(S, oS), - std::min(E, oE), std::min(N, oN)); - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct VerticalExtent::Private { - double minimum_{}; - double maximum_{}; - common::UnitOfMeasureNNPtr unit_; - - Private(double minimum, double maximum, - const common::UnitOfMeasureNNPtr &unit) - : minimum_(minimum), maximum_(maximum), unit_(unit) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -VerticalExtent::VerticalExtent(double minimumIn, double maximumIn, - const common::UnitOfMeasureNNPtr &unitIn) - : d(internal::make_unique<Private>(minimumIn, maximumIn, unitIn)) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -VerticalExtent::~VerticalExtent() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns the minimum of the vertical extent. - */ -double VerticalExtent::minimumValue() PROJ_CONST_DEFN { return d->minimum_; } - -// --------------------------------------------------------------------------- - -/** \brief Returns the maximum of the vertical extent. - */ -double VerticalExtent::maximumValue() PROJ_CONST_DEFN { return d->maximum_; } - -// --------------------------------------------------------------------------- - -/** \brief Returns the unit of the vertical extent. - */ -common::UnitOfMeasureNNPtr &VerticalExtent::unit() PROJ_CONST_DEFN { - return d->unit_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a VerticalExtent. - * - * @param minimumIn minimum. - * @param maximumIn maximum. - * @param unitIn unit. - * @return a new VerticalExtent. - */ -VerticalExtentNNPtr -VerticalExtent::create(double minimumIn, double maximumIn, - const common::UnitOfMeasureNNPtr &unitIn) { - return VerticalExtent::nn_make_shared<VerticalExtent>(minimumIn, maximumIn, - unitIn); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool VerticalExtent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion) const { - auto otherExtent = dynamic_cast<const VerticalExtent *>(other); - if (!otherExtent) - return false; - return d->minimum_ == otherExtent->d->minimum_ && - d->maximum_ == otherExtent->d->maximum_ && - d->unit_ == otherExtent->d->unit_; -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent contains the other one. - */ -bool VerticalExtent::contains(const VerticalExtentNNPtr &other) const { - const double thisUnitToSI = d->unit_->conversionToSI(); - const double otherUnitToSI = other->d->unit_->conversionToSI(); - return d->minimum_ * thisUnitToSI <= other->d->minimum_ * otherUnitToSI && - d->maximum_ * thisUnitToSI >= other->d->maximum_ * otherUnitToSI; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent intersects the other one. - */ -bool VerticalExtent::intersects(const VerticalExtentNNPtr &other) const { - const double thisUnitToSI = d->unit_->conversionToSI(); - const double otherUnitToSI = other->d->unit_->conversionToSI(); - return d->minimum_ * thisUnitToSI <= other->d->maximum_ * otherUnitToSI && - d->maximum_ * thisUnitToSI >= other->d->minimum_ * otherUnitToSI; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct TemporalExtent::Private { - std::string start_{}; - std::string stop_{}; - - Private(const std::string &start, const std::string &stop) - : start_(start), stop_(stop) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -TemporalExtent::TemporalExtent(const std::string &startIn, - const std::string &stopIn) - : d(internal::make_unique<Private>(startIn, stopIn)) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -TemporalExtent::~TemporalExtent() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns the start of the temporal extent. - */ -const std::string &TemporalExtent::start() PROJ_CONST_DEFN { return d->start_; } - -// --------------------------------------------------------------------------- - -/** \brief Returns the end of the temporal extent. - */ -const std::string &TemporalExtent::stop() PROJ_CONST_DEFN { return d->stop_; } - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a TemporalExtent. - * - * @param start start. - * @param stop stop. - * @return a new TemporalExtent. - */ -TemporalExtentNNPtr TemporalExtent::create(const std::string &start, - const std::string &stop) { - return TemporalExtent::nn_make_shared<TemporalExtent>(start, stop); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool TemporalExtent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion) const { - auto otherExtent = dynamic_cast<const TemporalExtent *>(other); - if (!otherExtent) - return false; - return start() == otherExtent->start() && stop() == otherExtent->stop(); -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent contains the other one. - */ -bool TemporalExtent::contains(const TemporalExtentNNPtr &other) const { - return start() <= other->start() && stop() >= other->stop(); -} - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent intersects the other one. - */ -bool TemporalExtent::intersects(const TemporalExtentNNPtr &other) const { - return start() <= other->stop() && stop() >= other->start(); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct Extent::Private { - optional<std::string> description_{}; - std::vector<GeographicExtentNNPtr> geographicElements_{}; - std::vector<VerticalExtentNNPtr> verticalElements_{}; - std::vector<TemporalExtentNNPtr> temporalElements_{}; -}; -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -Extent::Extent() : d(internal::make_unique<Private>()) {} - -// --------------------------------------------------------------------------- - -Extent::Extent(const Extent &other) - : d(internal::make_unique<Private>(*other.d)) {} - -// --------------------------------------------------------------------------- - -Extent::~Extent() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** Return a textual description of the extent. - * - * @return the description, or empty. - */ -const optional<std::string> &Extent::description() PROJ_CONST_DEFN { - return d->description_; -} - -// --------------------------------------------------------------------------- - -/** Return the geographic element(s) of the extent - * - * @return the geographic element(s), or empty. - */ -const std::vector<GeographicExtentNNPtr> & -Extent::geographicElements() PROJ_CONST_DEFN { - return d->geographicElements_; -} - -// --------------------------------------------------------------------------- - -/** Return the vertical element(s) of the extent - * - * @return the vertical element(s), or empty. - */ -const std::vector<VerticalExtentNNPtr> & -Extent::verticalElements() PROJ_CONST_DEFN { - return d->verticalElements_; -} - -// --------------------------------------------------------------------------- - -/** Return the temporal element(s) of the extent - * - * @return the temporal element(s), or empty. - */ -const std::vector<TemporalExtentNNPtr> & -Extent::temporalElements() PROJ_CONST_DEFN { - return d->temporalElements_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Extent. - * - * @param descriptionIn Textual description, or empty. - * @param geographicElementsIn Geographic element(s), or empty. - * @param verticalElementsIn Vertical element(s), or empty. - * @param temporalElementsIn Temporal element(s), or empty. - * @return a new Extent. - */ -ExtentNNPtr -Extent::create(const optional<std::string> &descriptionIn, - const std::vector<GeographicExtentNNPtr> &geographicElementsIn, - const std::vector<VerticalExtentNNPtr> &verticalElementsIn, - const std::vector<TemporalExtentNNPtr> &temporalElementsIn) { - auto extent = Extent::nn_make_shared<Extent>(); - extent->assignSelf(extent); - extent->d->description_ = descriptionIn; - extent->d->geographicElements_ = geographicElementsIn; - extent->d->verticalElements_ = verticalElementsIn; - extent->d->temporalElements_ = temporalElementsIn; - return extent; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Extent from a bounding box - * - * @param west Western-most coordinate of the limit of the dataset extent (in - * degrees). - * @param south Southern-most coordinate of the limit of the dataset extent (in - * degrees). - * @param east Eastern-most coordinate of the limit of the dataset extent (in - * degrees). - * @param north Northern-most coordinate of the limit of the dataset extent (in - * degrees). - * @param descriptionIn Textual description, or empty. - * @return a new Extent. - */ -ExtentNNPtr -Extent::createFromBBOX(double west, double south, double east, double north, - const util::optional<std::string> &descriptionIn) { - return create( - descriptionIn, - std::vector<GeographicExtentNNPtr>{ - nn_static_pointer_cast<GeographicExtent>( - GeographicBoundingBox::create(west, south, east, north))}, - std::vector<VerticalExtentNNPtr>(), std::vector<TemporalExtentNNPtr>()); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool Extent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { - auto otherExtent = dynamic_cast<const Extent *>(other); - bool ret = - (otherExtent && - description().has_value() == otherExtent->description().has_value() && - *description() == *otherExtent->description() && - d->geographicElements_.size() == - otherExtent->d->geographicElements_.size() && - d->verticalElements_.size() == - otherExtent->d->verticalElements_.size() && - d->temporalElements_.size() == - otherExtent->d->temporalElements_.size()); - if (ret) { - for (size_t i = 0; ret && i < d->geographicElements_.size(); ++i) { - ret = d->geographicElements_[i]->_isEquivalentTo( - otherExtent->d->geographicElements_[i].get(), criterion); - } - for (size_t i = 0; ret && i < d->verticalElements_.size(); ++i) { - ret = d->verticalElements_[i]->_isEquivalentTo( - otherExtent->d->verticalElements_[i].get(), criterion); - } - for (size_t i = 0; ret && i < d->temporalElements_.size(); ++i) { - ret = d->temporalElements_[i]->_isEquivalentTo( - otherExtent->d->temporalElements_[i].get(), criterion); - } - } - return ret; -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent contains the other one. - * - * Behaviour only well specified if each sub-extent category as at most - * one element. - */ -bool Extent::contains(const ExtentNNPtr &other) const { - bool res = true; - if (d->geographicElements_.size() == 1 && - other->d->geographicElements_.size() == 1) { - res = d->geographicElements_[0]->contains( - other->d->geographicElements_[0]); - } - if (res && d->verticalElements_.size() == 1 && - other->d->verticalElements_.size() == 1) { - res = d->verticalElements_[0]->contains(other->d->verticalElements_[0]); - } - if (res && d->temporalElements_.size() == 1 && - other->d->temporalElements_.size() == 1) { - res = d->temporalElements_[0]->contains(other->d->temporalElements_[0]); - } - return res; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns whether this extent intersects the other one. - * - * Behaviour only well specified if each sub-extent category as at most - * one element. - */ -bool Extent::intersects(const ExtentNNPtr &other) const { - bool res = true; - if (d->geographicElements_.size() == 1 && - other->d->geographicElements_.size() == 1) { - res = d->geographicElements_[0]->intersects( - other->d->geographicElements_[0]); - } - if (res && d->verticalElements_.size() == 1 && - other->d->verticalElements_.size() == 1) { - res = - d->verticalElements_[0]->intersects(other->d->verticalElements_[0]); - } - if (res && d->temporalElements_.size() == 1 && - other->d->temporalElements_.size() == 1) { - res = - d->temporalElements_[0]->intersects(other->d->temporalElements_[0]); - } - return res; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the intersection of this extent with another one. - * - * Behaviour only well specified if there is one single GeographicExtent - * in each object. - * Returns nullptr otherwise. - */ -ExtentPtr Extent::intersection(const ExtentNNPtr &other) const { - if (d->geographicElements_.size() == 1 && - other->d->geographicElements_.size() == 1) { - if (contains(other)) { - return other.as_nullable(); - } - auto self = util::nn_static_pointer_cast<Extent>(shared_from_this()); - if (other->contains(self)) { - return self.as_nullable(); - } - auto geogIntersection = d->geographicElements_[0]->intersection( - other->d->geographicElements_[0]); - if (geogIntersection) { - return create(util::optional<std::string>(), - std::vector<GeographicExtentNNPtr>{ - NN_NO_CHECK(geogIntersection)}, - std::vector<VerticalExtentNNPtr>{}, - std::vector<TemporalExtentNNPtr>{}); - } - } - return nullptr; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct Identifier::Private { - optional<Citation> authority_{}; - std::string code_{}; - optional<std::string> codeSpace_{}; - optional<std::string> version_{}; - optional<std::string> description_{}; - optional<std::string> uri_{}; - - Private() = default; - - Private(const std::string &codeIn, const PropertyMap &properties) - : code_(codeIn) { - setProperties(properties); - } - - private: - // cppcheck-suppress functionStatic - void setProperties(const PropertyMap &properties); -}; - -// --------------------------------------------------------------------------- - -void Identifier::Private::setProperties( - const PropertyMap &properties) // throw(InvalidValueTypeException) -{ - { - const auto pVal = properties.get(AUTHORITY_KEY); - if (pVal) { - if (auto genVal = dynamic_cast<const BoxedValue *>(pVal->get())) { - if (genVal->type() == BoxedValue::Type::STRING) { - authority_ = Citation(genVal->stringValue()); - } else { - throw InvalidValueTypeException("Invalid value type for " + - AUTHORITY_KEY); - } - } else { - if (auto citation = - dynamic_cast<const Citation *>(pVal->get())) { - authority_ = *citation; - } else { - throw InvalidValueTypeException("Invalid value type for " + - AUTHORITY_KEY); - } - } - } - } - - { - const auto pVal = properties.get(CODE_KEY); - if (pVal) { - if (auto genVal = dynamic_cast<const BoxedValue *>(pVal->get())) { - if (genVal->type() == BoxedValue::Type::INTEGER) { - code_ = toString(genVal->integerValue()); - } else if (genVal->type() == BoxedValue::Type::STRING) { - code_ = genVal->stringValue(); - } else { - throw InvalidValueTypeException("Invalid value type for " + - CODE_KEY); - } - } else { - throw InvalidValueTypeException("Invalid value type for " + - CODE_KEY); - } - } - } - - properties.getStringValue(CODESPACE_KEY, codeSpace_); - properties.getStringValue(VERSION_KEY, version_); - properties.getStringValue(DESCRIPTION_KEY, description_); - properties.getStringValue(URI_KEY, uri_); -} - -//! @endcond - -// --------------------------------------------------------------------------- - -Identifier::Identifier(const std::string &codeIn, - const util::PropertyMap &properties) - : d(internal::make_unique<Private>(codeIn, properties)) {} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress - -// --------------------------------------------------------------------------- - -Identifier::Identifier() : d(internal::make_unique<Private>()) {} - -// --------------------------------------------------------------------------- - -Identifier::Identifier(const Identifier &other) - : d(internal::make_unique<Private>(*(other.d))) {} - -// --------------------------------------------------------------------------- - -Identifier::~Identifier() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a Identifier. - * - * @param codeIn Alphanumeric value identifying an instance in the codespace - * @param properties See \ref general_properties. - * Generally, the Identifier::CODESPACE_KEY should be set. - * @return a new Identifier. - */ -IdentifierNNPtr Identifier::create(const std::string &codeIn, - const PropertyMap &properties) { - return Identifier::nn_make_shared<Identifier>(codeIn, properties); -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -IdentifierNNPtr -Identifier::createFromDescription(const std::string &descriptionIn) { - auto id = Identifier::nn_make_shared<Identifier>(); - id->d->description_ = descriptionIn; - return id; -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return a citation for the organization responsible for definition and - * maintenance of the code. - * - * @return the citation for the authority, or empty. - */ -const optional<Citation> &Identifier::authority() PROJ_CONST_DEFN { - return d->authority_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the alphanumeric value identifying an instance in the - * codespace. - * - * e.g. "4326" (for EPSG:4326 WGS 84 GeographicCRS) - * - * @return the code. - */ -const std::string &Identifier::code() PROJ_CONST_DEFN { return d->code_; } - -// --------------------------------------------------------------------------- - -/** \brief Return the organization responsible for definition and maintenance of - * the code. - * - * e.g "EPSG" - * - * @return the authority codespace, or empty. - */ -const optional<std::string> &Identifier::codeSpace() PROJ_CONST_DEFN { - return d->codeSpace_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the version identifier for the namespace. - * - * When appropriate, the edition is identified by the effective date, coded - * using ISO 8601 date format. - * - * @return the version or empty. - */ -const optional<std::string> &Identifier::version() PROJ_CONST_DEFN { - return d->version_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the natural language description of the meaning of the code - * value. - * - * @return the description or empty. - */ -const optional<std::string> &Identifier::description() PROJ_CONST_DEFN { - return d->description_; -} - -// --------------------------------------------------------------------------- - -/** \brief Return the URI of the identifier. - * - * @return the URI or empty. - */ -const optional<std::string> &Identifier::uri() PROJ_CONST_DEFN { - return d->uri_; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void Identifier::_exportToWKT(WKTFormatter *formatter) const { - const bool isWKT2 = formatter->version() == WKTFormatter::Version::WKT2; - const std::string &l_code = code(); - const std::string &l_codeSpace = *codeSpace(); - if (!l_codeSpace.empty() && !l_code.empty()) { - if (isWKT2) { - formatter->startNode(WKTConstants::ID, false); - formatter->addQuotedString(l_codeSpace); - try { - (void)std::stoi(l_code); - formatter->add(l_code); - } catch (const std::exception &) { - formatter->addQuotedString(l_code); - } - if (version().has_value()) { - auto l_version = *(version()); - try { - (void)c_locale_stod(l_version); - formatter->add(l_version); - } catch (const std::exception &) { - formatter->addQuotedString(l_version); - } - } - if (authority().has_value() && - *(authority()->title()) != l_codeSpace) { - formatter->startNode(WKTConstants::CITATION, false); - formatter->addQuotedString(*(authority()->title())); - formatter->endNode(); - } - if (uri().has_value()) { - formatter->startNode(WKTConstants::URI, false); - formatter->addQuotedString(*(uri())); - formatter->endNode(); - } - formatter->endNode(); - } else { - formatter->startNode(WKTConstants::AUTHORITY, false); - formatter->addQuotedString(l_codeSpace); - formatter->addQuotedString(l_code); - formatter->endNode(); - } - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -static bool isIgnoredChar(char ch) { - return ch == ' ' || ch == '_' || ch == '-' || ch == '/' || ch == '(' || - ch == ')' || ch == '.' || ch == '&'; -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -static const struct utf8_to_lower { - const char *utf8; - char ascii; -} map_utf8_to_lower[] = { - {"\xc3\xa1", 'a'}, // a acute - {"\xc3\xa4", 'a'}, // a tremma - - {"\xc4\x9b", 'e'}, // e reverse circumflex - {"\xc3\xa8", 'e'}, // e grave - {"\xc3\xa9", 'e'}, // e acute - {"\xc3\xab", 'e'}, // e tremma - - {"\xc3\xad", 'i'}, // i grave - - {"\xc3\xb4", 'o'}, // o circumflex - {"\xc3\xb6", 'o'}, // o tremma - - {"\xc3\xa7", 'c'}, // c cedilla -}; - -static const struct utf8_to_lower *get_ascii_replacement(const char *c_str) { - for (const auto &pair : map_utf8_to_lower) { - if (*c_str == pair.utf8[0] && - strncmp(c_str, pair.utf8, strlen(pair.utf8)) == 0) { - return &pair; - } - } - return nullptr; -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -std::string Identifier::canonicalizeName(const std::string &str) { - std::string res; - const char *c_str = str.c_str(); - for (size_t i = 0; c_str[i] != 0; ++i) { - const auto ch = c_str[i]; - if (ch == ' ' && c_str[i + 1] == '+' && c_str[i + 2] == ' ') { - i += 2; - continue; - } - if (ch == '1' && !res.empty() && - !(res.back() >= '0' && res.back() <= '9') && c_str[i + 1] == '9' && - c_str[i + 2] >= '0' && c_str[i + 2] <= '9') { - ++i; - continue; - } - if (static_cast<unsigned char>(ch) > 127) { - const auto *replacement = get_ascii_replacement(c_str + i); - if (replacement) { - res.push_back(replacement->ascii); - i += strlen(replacement->utf8) - 1; - continue; - } - } - if (!isIgnoredChar(ch)) { - res.push_back(static_cast<char>(::tolower(ch))); - } - } - return res; -} -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Returns whether two names are considered equivalent. - * - * Two names are equivalent by removing any space, underscore, dash, slash, - * { or } character from them, and comparing in a case insensitive way. - */ -bool Identifier::isEquivalentName(const char *a, const char *b) noexcept { - size_t i = 0; - size_t j = 0; - char lastValidA = 0; - char lastValidB = 0; - while (a[i] != 0 && b[j] != 0) { - char aCh = a[i]; - char bCh = b[j]; - if (aCh == ' ' && a[i + 1] == '+' && a[i + 2] == ' ') { - i += 3; - continue; - } - if (bCh == ' ' && b[j + 1] == '+' && b[j + 2] == ' ') { - j += 3; - continue; - } - if (isIgnoredChar(aCh)) { - ++i; - continue; - } - if (isIgnoredChar(bCh)) { - ++j; - continue; - } - if (aCh == '1' && !(lastValidA >= '0' && lastValidA <= '9') && - a[i + 1] == '9' && a[i + 2] >= '0' && a[i + 2] <= '9') { - i += 2; - lastValidA = '9'; - continue; - } - if (bCh == '1' && !(lastValidB >= '0' && lastValidB <= '9') && - b[j + 1] == '9' && b[j + 2] >= '0' && b[j + 2] <= '9') { - j += 2; - lastValidB = '9'; - continue; - } - if (static_cast<unsigned char>(aCh) > 127) { - const auto *replacement = get_ascii_replacement(a + i); - if (replacement) { - aCh = replacement->ascii; - i += strlen(replacement->utf8) - 1; - } - } - if (static_cast<unsigned char>(bCh) > 127) { - const auto *replacement = get_ascii_replacement(b + j); - if (replacement) { - bCh = replacement->ascii; - j += strlen(replacement->utf8) - 1; - } - } - if (::tolower(aCh) != ::tolower(bCh)) { - return false; - } - lastValidA = aCh; - lastValidB = bCh; - ++i; - ++j; - } - while (a[i] != 0 && isIgnoredChar(a[i])) { - ++i; - } - while (b[j] != 0 && isIgnoredChar(b[j])) { - ++j; - } - return a[i] == b[j]; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct PositionalAccuracy::Private { - std::string value_{}; -}; -//! @endcond - -// --------------------------------------------------------------------------- - -PositionalAccuracy::PositionalAccuracy(const std::string &valueIn) - : d(internal::make_unique<Private>()) { - d->value_ = valueIn; -} - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -PositionalAccuracy::~PositionalAccuracy() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -/** \brief Return the value of the positional accuracy. - */ -const std::string &PositionalAccuracy::value() PROJ_CONST_DEFN { - return d->value_; -} - -// --------------------------------------------------------------------------- - -/** \brief Instanciate a PositionalAccuracy. - * - * @param valueIn positional accuracy value. - * @return a new PositionalAccuracy. - */ -PositionalAccuracyNNPtr PositionalAccuracy::create(const std::string &valueIn) { - return PositionalAccuracy::nn_make_shared<PositionalAccuracy>(valueIn); -} - -} // namespace metadata -NS_PROJ_END |
