From d93fc9adc38386d4092219ce28004e1351dea31e Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 3 Jan 2025 01:15:04 +0100 Subject: [PATCH 1/4] CI: update clang_static_analyzer to ubuntu-24.04 to avoid false positives --- .github/workflows/clang_static_analyzer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang_static_analyzer.yml b/.github/workflows/clang_static_analyzer.yml index b6433b2433..1985c96a64 100644 --- a/.github/workflows/clang_static_analyzer.yml +++ b/.github/workflows/clang_static_analyzer.yml @@ -18,7 +18,7 @@ permissions: jobs: clang_static_analyzer: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - name: Checkout From 0911ff3c690a795dc46a3efcc55baeaf1b8592c3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 3 Jan 2025 01:34:36 +0100 Subject: [PATCH 2/4] Rework code a bit to avoid false positive CSA warnings in C++17 mode --- src/iso19111/coordinates.cpp | 19 ++-- src/iso19111/datum.cpp | 18 ++-- src/iso19111/factory.cpp | 4 +- src/iso19111/io.cpp | 4 +- src/iso19111/operation/singleoperation.cpp | 101 ++++++++++----------- 5 files changed, 74 insertions(+), 72 deletions(-) diff --git a/src/iso19111/coordinates.cpp b/src/iso19111/coordinates.cpp index a51763d88e..21751f294a 100644 --- a/src/iso19111/coordinates.cpp +++ b/src/iso19111/coordinates.cpp @@ -213,13 +213,18 @@ CoordinateMetadataNNPtr CoordinateMetadata::promoteTo3D(const std::string &newName, const io::DatabaseContextPtr &dbContext) const { auto crs = d->crs_->promoteTo3D(newName, dbContext); - auto coordinateMetadata( - d->coordinateEpoch_.has_value() - ? CoordinateMetadata::nn_make_shared( - crs, coordinateEpochAsDecimalYear()) - : CoordinateMetadata::nn_make_shared(crs)); - coordinateMetadata->assignSelf(coordinateMetadata); - return coordinateMetadata; + if (d->coordinateEpoch_.has_value()) { + auto coordinateMetadata( + CoordinateMetadata::nn_make_shared( + crs, coordinateEpochAsDecimalYear())); + coordinateMetadata->assignSelf(coordinateMetadata); + return coordinateMetadata; + } else { + auto coordinateMetadata( + CoordinateMetadata::nn_make_shared(crs)); + coordinateMetadata->assignSelf(coordinateMetadata); + return coordinateMetadata; + } } // --------------------------------------------------------------------------- diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 8c89c2d70c..9baa1d0faf 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -818,13 +818,17 @@ EllipsoidNNPtr Ellipsoid::createSphere(const util::PropertyMap &properties, EllipsoidNNPtr Ellipsoid::createFlattenedSphere( const util::PropertyMap &properties, const common::Length &semiMajorAxisIn, const common::Scale &invFlattening, const std::string &celestialBody) { - auto ellipsoid(invFlattening.value() == 0 - ? Ellipsoid::nn_make_shared(semiMajorAxisIn, - celestialBody) - : Ellipsoid::nn_make_shared( - semiMajorAxisIn, invFlattening, celestialBody)); - ellipsoid->setProperties(properties); - return ellipsoid; + if (invFlattening.value() == 0) { + auto ellipsoid(Ellipsoid::nn_make_shared(semiMajorAxisIn, + celestialBody)); + ellipsoid->setProperties(properties); + return ellipsoid; + } else { + auto ellipsoid(Ellipsoid::nn_make_shared( + semiMajorAxisIn, invFlattening, celestialBody)); + ellipsoid->setProperties(properties); + return ellipsoid; + } } // --------------------------------------------------------------------------- diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 5550fd430d..3a8e25551d 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -3114,9 +3114,9 @@ std::string DatabaseContext::suggestsCodeFor(const common::IdentifiedObjectNNPtr &object, const std::string &authName, bool numericCode) { - const char *tableName = ""; + const char *tableName = "prime_meridian"; if (dynamic_cast(object.get())) { - tableName = "prime_meridian"; + // tableName = "prime_meridian"; } else if (dynamic_cast(object.get())) { tableName = "ellipsoid"; } else if (dynamic_cast( diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 3695408442..a7ac827049 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -2832,9 +2832,9 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */ children[1]->GP()->value())); } } else { - const char *csTypeCStr = ""; + const char *csTypeCStr = CartesianCS::WKT2_TYPE; if (ci_equal(parentNodeName, WKTConstants::GEOCCS)) { - csTypeCStr = CartesianCS::WKT2_TYPE; + // csTypeCStr = CartesianCS::WKT2_TYPE; isGeocentric = true; if (axisCount == 0) { auto unit = diff --git a/src/iso19111/operation/singleoperation.cpp b/src/iso19111/operation/singleoperation.cpp index 22400f6fb0..15d517d393 100644 --- a/src/iso19111/operation/singleoperation.cpp +++ b/src/iso19111/operation/singleoperation.cpp @@ -45,6 +45,7 @@ #include "operationmethod_private.hpp" #include "oputils.hpp" #include "parammappings.hpp" +#include "vectorofvaluesparams.hpp" // PROJ include order is sensitive // clang-format off @@ -2285,18 +2286,13 @@ createNTv1(const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn, const std::string &filename, const std::vector &accuracies) { + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE)}; + const VectorOfValues values{ParameterValue::createFilename(filename)}; return Transformation::create( properties, sourceCRSIn, targetCRSIn, nullptr, - createMethodMapNameEPSGCode(EPSG_CODE_METHOD_NTV1), - {OperationParameter::create( - util::PropertyMap() - .set(common::IdentifiedObject::NAME_KEY, - EPSG_NAME_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE) - .set(metadata::Identifier::CODESPACE_KEY, - metadata::Identifier::EPSG) - .set(metadata::Identifier::CODE_KEY, - EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE))}, - {ParameterValue::createFilename(filename)}, accuracies); + createMethodMapNameEPSGCode(EPSG_CODE_METHOD_NTV1), parameters, values, + accuracies); } //! @endcond @@ -2417,7 +2413,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); const auto &l_accuracies = coordinateOperationAccuracies(); if (projGridFormat == "GTiff") { - auto parameters = std::vector{ + const VectorOfParameters parameters{ methodEPSGCode == EPSG_CODE_METHOD_NADCON5_3D ? OperationParameter::create(util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, @@ -2430,7 +2426,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( methodEPSGCode == EPSG_CODE_METHOD_NADCON5_3D) ? PROJ_WKT2_NAME_METHOD_GENERAL_SHIFT_GTIFF : PROJ_WKT2_NAME_METHOD_HORIZONTAL_SHIFT_GTIFF); - auto values = std::vector{ + const VectorOfValues values{ ParameterValue::createFilename(projFilename)}; if (inverseDirection) { return Transformation::create( @@ -2471,13 +2467,12 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( l_targetCRS, projFilename, l_accuracies); } } else if (projGridFormat == "CTable2") { - auto parameters = - std::vector{createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE)}; auto methodProperties = util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, PROJ_WKT2_NAME_METHOD_CTABLE2); - auto values = std::vector{ + const VectorOfValues values{ ParameterValue::createFilename(projFilename)}; if (inverseDirection) { return Transformation::create( @@ -2528,9 +2523,10 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = std::vector{ - createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; #ifdef disabled_for_now if (inverseDirection) { return Transformation::create( @@ -2538,8 +2534,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( self.as_nullable().get(), true, false), l_targetCRS, l_sourceCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), - parameters, - {ParameterValue::createFilename(projFilename)}, + parameters, values, coordinateOperationAccuracies()) ->inverseAsTransformation(); } else @@ -2549,8 +2544,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, - coordinateOperationAccuracies()); + values, coordinateOperationAccuracies()); } } } @@ -2583,14 +2577,14 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = - std::vector{createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; return Transformation::create( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, - createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, + createSimilarPropertiesMethod(method()), parameters, values, coordinateOperationAccuracies()); } } @@ -2622,14 +2616,14 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = - std::vector{createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; return Transformation::create( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, - createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, + createSimilarPropertiesMethod(method()), parameters, values, coordinateOperationAccuracies()); } } @@ -2661,14 +2655,14 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = - std::vector{createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; return Transformation::create( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, - createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, + createSimilarPropertiesMethod(method()), parameters, values, coordinateOperationAccuracies()); } } @@ -2712,16 +2706,17 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = std::vector{ + const VectorOfParameters parameters{ createOpParamNameEPSGCode(parameterCode)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; if (inverseDirection) { return Transformation::create( createPropertiesForInverse( self.as_nullable().get(), true, false), l_targetCRS, l_sourceCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), - parameters, - {ParameterValue::createFilename(projFilename)}, + parameters, values, coordinateOperationAccuracies()) ->inverseAsTransformation(); } else { @@ -2729,8 +2724,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, - coordinateOperationAccuracies()); + values, coordinateOperationAccuracies()); } } } @@ -2786,18 +2780,18 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( } auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull); auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull); - auto parameters = std::vector{ + const VectorOfParameters parameters{ createOpParamNameEPSGCode( gridTransf.gridFilenameParamEPSGCode)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; if (inverseDirection) { return Transformation::create( createPropertiesForInverse( self.as_nullable().get(), true, false), l_targetCRS, l_sourceCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), - parameters, - {ParameterValue::createFilename( - projFilename)}, + parameters, values, coordinateOperationAccuracies()) ->inverseAsTransformation(); } else { @@ -2805,8 +2799,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( createSimilarPropertiesOperation(self), l_sourceCRS, l_targetCRS, l_interpolationCRS, createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, - coordinateOperationAccuracies()); + values, coordinateOperationAccuracies()); } } } @@ -5162,13 +5155,13 @@ PointMotionOperation::substitutePROJAlternativeGridNames( return self; } - auto parameters = - std::vector{createOpParamNameEPSGCode( - EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfParameters parameters{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)}; + const VectorOfValues values{ + ParameterValue::createFilename(projFilename)}; return PointMotionOperation::create( createSimilarPropertiesOperation(self), sourceCRS(), - createSimilarPropertiesMethod(method()), parameters, - {ParameterValue::createFilename(projFilename)}, + createSimilarPropertiesMethod(method()), parameters, values, coordinateOperationAccuracies()); } From 16b75c1cbce5b1d404b1f5ae579a1e8cb1eb4334 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 3 Jan 2025 03:02:31 +0100 Subject: [PATCH 3/4] Move ParameterValue class members to a dedicated .cpp files to avoid false-positive from CSA --- src/iso19111/operation/parametervalue.cpp | 333 +++++++++++++++++++++ src/iso19111/operation/singleoperation.cpp | 278 ----------------- src/lib_proj.cmake | 1 + 3 files changed, 334 insertions(+), 278 deletions(-) create mode 100644 src/iso19111/operation/parametervalue.cpp diff --git a/src/iso19111/operation/parametervalue.cpp b/src/iso19111/operation/parametervalue.cpp new file mode 100644 index 0000000000..33f907fe7c --- /dev/null +++ b/src/iso19111/operation/parametervalue.cpp @@ -0,0 +1,333 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: ISO19111:2019 implementation + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2018, Even Rouault + * + * 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/common.hpp" +#include "proj/coordinateoperation.hpp" +#include "proj/util.hpp" + +#include "proj/internal/internal.hpp" + +#include +#include +#include +#include +#include + +using namespace NS_PROJ::internal; + +// --------------------------------------------------------------------------- + +NS_PROJ_START +namespace operation { + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +struct ParameterValue::Private { + ParameterValue::Type type_{ParameterValue::Type::STRING}; + std::unique_ptr measure_{}; + std::unique_ptr stringValue_{}; + int integerValue_{}; + bool booleanValue_{}; + + explicit Private(const common::Measure &valueIn) + : type_(ParameterValue::Type::MEASURE), + measure_(internal::make_unique(valueIn)) {} + + Private(const std::string &stringValueIn, ParameterValue::Type typeIn) + : type_(typeIn), + stringValue_(internal::make_unique(stringValueIn)) {} + + explicit Private(int integerValueIn) + : type_(ParameterValue::Type::INTEGER), integerValue_(integerValueIn) {} + + explicit Private(bool booleanValueIn) + : type_(ParameterValue::Type::BOOLEAN), booleanValue_(booleanValueIn) {} +}; +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +ParameterValue::~ParameterValue() = default; +//! @endcond + +// --------------------------------------------------------------------------- + +ParameterValue::ParameterValue(const common::Measure &measureIn) + : d(internal::make_unique(measureIn)) {} + +// --------------------------------------------------------------------------- + +ParameterValue::ParameterValue(const std::string &stringValueIn, + ParameterValue::Type typeIn) + : d(internal::make_unique(stringValueIn, typeIn)) {} + +// --------------------------------------------------------------------------- + +ParameterValue::ParameterValue(int integerValueIn) + : d(internal::make_unique(integerValueIn)) {} + +// --------------------------------------------------------------------------- + +ParameterValue::ParameterValue(bool booleanValueIn) + : d(internal::make_unique(booleanValueIn)) {} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a Measure (i.e. a value associated + * with a + * unit) + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr ParameterValue::create(const common::Measure &measureIn) { + return ParameterValue::nn_make_shared(measureIn); +} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a string value. + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr ParameterValue::create(const char *stringValueIn) { + return ParameterValue::nn_make_shared( + std::string(stringValueIn), ParameterValue::Type::STRING); +} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a string value. + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr ParameterValue::create(const std::string &stringValueIn) { + return ParameterValue::nn_make_shared( + stringValueIn, ParameterValue::Type::STRING); +} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a filename. + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr +ParameterValue::createFilename(const std::string &stringValueIn) { + return ParameterValue::nn_make_shared( + stringValueIn, ParameterValue::Type::FILENAME); +} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a integer value. + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr ParameterValue::create(int integerValueIn) { + return ParameterValue::nn_make_shared(integerValueIn); +} + +// --------------------------------------------------------------------------- + +/** \brief Instantiate a ParameterValue from a boolean value. + * + * @return a new ParameterValue. + */ +ParameterValueNNPtr ParameterValue::create(bool booleanValueIn) { + return ParameterValue::nn_make_shared(booleanValueIn); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the type of a parameter value. + * + * @return the type. + */ +const ParameterValue::Type &ParameterValue::type() PROJ_PURE_DEFN { + return d->type_; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the value as a Measure (assumes type() == Type::MEASURE) + * @return the value as a Measure. + */ +const common::Measure &ParameterValue::value() PROJ_PURE_DEFN { + return *d->measure_; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the value as a string (assumes type() == Type::STRING) + * @return the value as a string. + */ +const std::string &ParameterValue::stringValue() PROJ_PURE_DEFN { + return *d->stringValue_; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the value as a filename (assumes type() == Type::FILENAME) + * @return the value as a filename. + */ +const std::string &ParameterValue::valueFile() PROJ_PURE_DEFN { + return *d->stringValue_; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the value as a integer (assumes type() == Type::INTEGER) + * @return the value as a integer. + */ +int ParameterValue::integerValue() PROJ_PURE_DEFN { return d->integerValue_; } + +// --------------------------------------------------------------------------- + +/** \brief Returns the value as a boolean (assumes type() == Type::BOOLEAN) + * @return the value as a boolean. + */ +bool ParameterValue::booleanValue() PROJ_PURE_DEFN { return d->booleanValue_; } + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +void ParameterValue::_exportToWKT(io::WKTFormatter *formatter) const { + const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; + + const auto &l_type = type(); + if (l_type == Type::MEASURE) { + const auto &l_value = value(); + if (formatter->abridgedTransformation()) { + const auto &unit = l_value.unit(); + const auto &unitType = unit.type(); + if (unitType == common::UnitOfMeasure::Type::LINEAR) { + formatter->add(l_value.getSIValue()); + } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { + formatter->add( + l_value.convertToUnit(common::UnitOfMeasure::ARC_SECOND)); + } else if (unit == common::UnitOfMeasure::PARTS_PER_MILLION) { + formatter->add(1.0 + l_value.value() * 1e-6); + } else { + formatter->add(l_value.value()); + } + } else { + const auto &unit = l_value.unit(); + if (isWKT2) { + formatter->add(l_value.value()); + } else { + // In WKT1, as we don't output the natural unit, output to the + // registered linear / angular unit. + const auto &unitType = unit.type(); + if (unitType == common::UnitOfMeasure::Type::LINEAR) { + const auto &targetUnit = *(formatter->axisLinearUnit()); + if (targetUnit.conversionToSI() == 0.0) { + throw io::FormattingException( + "cannot convert value to target linear unit"); + } + formatter->add(l_value.convertToUnit(targetUnit)); + } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { + const auto &targetUnit = *(formatter->axisAngularUnit()); + if (targetUnit.conversionToSI() == 0.0) { + throw io::FormattingException( + "cannot convert value to target angular unit"); + } + formatter->add(l_value.convertToUnit(targetUnit)); + } else { + formatter->add(l_value.getSIValue()); + } + } + if (isWKT2 && unit != common::UnitOfMeasure::NONE) { + if (!formatter + ->primeMeridianOrParameterUnitOmittedIfSameAsAxis() || + (unit != common::UnitOfMeasure::SCALE_UNITY && + unit != *(formatter->axisLinearUnit()) && + unit != *(formatter->axisAngularUnit()))) { + unit._exportToWKT(formatter); + } + } + } + } else if (l_type == Type::STRING || l_type == Type::FILENAME) { + formatter->addQuotedString(stringValue()); + } else if (l_type == Type::INTEGER) { + formatter->add(integerValue()); + } else { + throw io::FormattingException("boolean parameter value not handled"); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +bool ParameterValue::_isEquivalentTo(const util::IComparable *other, + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &) const { + auto otherPV = dynamic_cast(other); + if (otherPV == nullptr) { + return false; + } + if (type() != otherPV->type()) { + return false; + } + switch (type()) { + case Type::MEASURE: { + return value()._isEquivalentTo(otherPV->value(), criterion, 2e-10); + } + + case Type::STRING: + case Type::FILENAME: { + return stringValue() == otherPV->stringValue(); + } + + case Type::INTEGER: { + return integerValue() == otherPV->integerValue(); + } + + case Type::BOOLEAN: { + return booleanValue() == otherPV->booleanValue(); + } + + default: { + assert(false); + break; + } + } + return true; +} +//! @endcond +// --------------------------------------------------------------------------- + +} // namespace operation + +NS_PROJ_END diff --git a/src/iso19111/operation/singleoperation.cpp b/src/iso19111/operation/singleoperation.cpp index 15d517d393..9a6221072c 100644 --- a/src/iso19111/operation/singleoperation.cpp +++ b/src/iso19111/operation/singleoperation.cpp @@ -2810,284 +2810,6 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames( return self; } -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -struct ParameterValue::Private { - ParameterValue::Type type_{ParameterValue::Type::STRING}; - std::unique_ptr measure_{}; - std::unique_ptr stringValue_{}; - int integerValue_{}; - bool booleanValue_{}; - - explicit Private(const common::Measure &valueIn) - : type_(ParameterValue::Type::MEASURE), - measure_(internal::make_unique(valueIn)) {} - - Private(const std::string &stringValueIn, ParameterValue::Type typeIn) - : type_(typeIn), - stringValue_(internal::make_unique(stringValueIn)) {} - - explicit Private(int integerValueIn) - : type_(ParameterValue::Type::INTEGER), integerValue_(integerValueIn) {} - - explicit Private(bool booleanValueIn) - : type_(ParameterValue::Type::BOOLEAN), booleanValue_(booleanValueIn) {} -}; -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -ParameterValue::~ParameterValue() = default; -//! @endcond - -// --------------------------------------------------------------------------- - -ParameterValue::ParameterValue(const common::Measure &measureIn) - : d(internal::make_unique(measureIn)) {} - -// --------------------------------------------------------------------------- - -ParameterValue::ParameterValue(const std::string &stringValueIn, - ParameterValue::Type typeIn) - : d(internal::make_unique(stringValueIn, typeIn)) {} - -// --------------------------------------------------------------------------- - -ParameterValue::ParameterValue(int integerValueIn) - : d(internal::make_unique(integerValueIn)) {} - -// --------------------------------------------------------------------------- - -ParameterValue::ParameterValue(bool booleanValueIn) - : d(internal::make_unique(booleanValueIn)) {} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a Measure (i.e. a value associated - * with a - * unit) - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr ParameterValue::create(const common::Measure &measureIn) { - return ParameterValue::nn_make_shared(measureIn); -} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a string value. - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr ParameterValue::create(const char *stringValueIn) { - return ParameterValue::nn_make_shared( - std::string(stringValueIn), ParameterValue::Type::STRING); -} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a string value. - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr ParameterValue::create(const std::string &stringValueIn) { - return ParameterValue::nn_make_shared( - stringValueIn, ParameterValue::Type::STRING); -} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a filename. - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr -ParameterValue::createFilename(const std::string &stringValueIn) { - return ParameterValue::nn_make_shared( - stringValueIn, ParameterValue::Type::FILENAME); -} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a integer value. - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr ParameterValue::create(int integerValueIn) { - return ParameterValue::nn_make_shared(integerValueIn); -} - -// --------------------------------------------------------------------------- - -/** \brief Instantiate a ParameterValue from a boolean value. - * - * @return a new ParameterValue. - */ -ParameterValueNNPtr ParameterValue::create(bool booleanValueIn) { - return ParameterValue::nn_make_shared(booleanValueIn); -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the type of a parameter value. - * - * @return the type. - */ -const ParameterValue::Type &ParameterValue::type() PROJ_PURE_DEFN { - return d->type_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the value as a Measure (assumes type() == Type::MEASURE) - * @return the value as a Measure. - */ -const common::Measure &ParameterValue::value() PROJ_PURE_DEFN { - return *d->measure_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the value as a string (assumes type() == Type::STRING) - * @return the value as a string. - */ -const std::string &ParameterValue::stringValue() PROJ_PURE_DEFN { - return *d->stringValue_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the value as a filename (assumes type() == Type::FILENAME) - * @return the value as a filename. - */ -const std::string &ParameterValue::valueFile() PROJ_PURE_DEFN { - return *d->stringValue_; -} - -// --------------------------------------------------------------------------- - -/** \brief Returns the value as a integer (assumes type() == Type::INTEGER) - * @return the value as a integer. - */ -int ParameterValue::integerValue() PROJ_PURE_DEFN { return d->integerValue_; } - -// --------------------------------------------------------------------------- - -/** \brief Returns the value as a boolean (assumes type() == Type::BOOLEAN) - * @return the value as a boolean. - */ -bool ParameterValue::booleanValue() PROJ_PURE_DEFN { return d->booleanValue_; } - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -void ParameterValue::_exportToWKT(io::WKTFormatter *formatter) const { - const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - - const auto &l_type = type(); - if (l_type == Type::MEASURE) { - const auto &l_value = value(); - if (formatter->abridgedTransformation()) { - const auto &unit = l_value.unit(); - const auto &unitType = unit.type(); - if (unitType == common::UnitOfMeasure::Type::LINEAR) { - formatter->add(l_value.getSIValue()); - } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { - formatter->add( - l_value.convertToUnit(common::UnitOfMeasure::ARC_SECOND)); - } else if (unit == common::UnitOfMeasure::PARTS_PER_MILLION) { - formatter->add(1.0 + l_value.value() * 1e-6); - } else { - formatter->add(l_value.value()); - } - } else { - const auto &unit = l_value.unit(); - if (isWKT2) { - formatter->add(l_value.value()); - } else { - // In WKT1, as we don't output the natural unit, output to the - // registered linear / angular unit. - const auto &unitType = unit.type(); - if (unitType == common::UnitOfMeasure::Type::LINEAR) { - const auto &targetUnit = *(formatter->axisLinearUnit()); - if (targetUnit.conversionToSI() == 0.0) { - throw io::FormattingException( - "cannot convert value to target linear unit"); - } - formatter->add(l_value.convertToUnit(targetUnit)); - } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { - const auto &targetUnit = *(formatter->axisAngularUnit()); - if (targetUnit.conversionToSI() == 0.0) { - throw io::FormattingException( - "cannot convert value to target angular unit"); - } - formatter->add(l_value.convertToUnit(targetUnit)); - } else { - formatter->add(l_value.getSIValue()); - } - } - if (isWKT2 && unit != common::UnitOfMeasure::NONE) { - if (!formatter - ->primeMeridianOrParameterUnitOmittedIfSameAsAxis() || - (unit != common::UnitOfMeasure::SCALE_UNITY && - unit != *(formatter->axisLinearUnit()) && - unit != *(formatter->axisAngularUnit()))) { - unit._exportToWKT(formatter); - } - } - } - } else if (l_type == Type::STRING || l_type == Type::FILENAME) { - formatter->addQuotedString(stringValue()); - } else if (l_type == Type::INTEGER) { - formatter->add(integerValue()); - } else { - throw io::FormattingException("boolean parameter value not handled"); - } -} -//! @endcond - -// --------------------------------------------------------------------------- - -//! @cond Doxygen_Suppress -bool ParameterValue::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion, - const io::DatabaseContextPtr &) const { - auto otherPV = dynamic_cast(other); - if (otherPV == nullptr) { - return false; - } - if (type() != otherPV->type()) { - return false; - } - switch (type()) { - case Type::MEASURE: { - return value()._isEquivalentTo(otherPV->value(), criterion, 2e-10); - } - - case Type::STRING: - case Type::FILENAME: { - return stringValue() == otherPV->stringValue(); - } - - case Type::INTEGER: { - return integerValue() == otherPV->integerValue(); - } - - case Type::BOOLEAN: { - return booleanValue() == otherPV->booleanValue(); - } - - default: { - assert(false); - break; - } - } - return true; -} -//! @endcond - //! @cond Doxygen_Suppress // --------------------------------------------------------------------------- diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index d82da7cfa6..7e3da03b60 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -186,6 +186,7 @@ set(SRC_LIBPROJ_ISO19111 iso19111/operation/conversion.cpp iso19111/operation/esriparammappings.cpp iso19111/operation/oputils.cpp + iso19111/operation/parametervalue.cpp iso19111/operation/parammappings.cpp iso19111/operation/projbasedoperation.cpp iso19111/operation/singleoperation.cpp From cdd7809e73523f9d99b31c256940835640e2e94d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 3 Jan 2025 00:25:45 +0100 Subject: [PATCH 4/4] Build: Update to C++17 version The immediate driver for this change is related when fetching GTest. Currently we are stuck with GTest-1.12.1 because is the latest version supporting C++11. Later versions require C++14. However, GTest-1.12.1 has a CMakeLists.txt with ``cmake_minimum_required(VERSION 3.5)`` which causes the following warning with modern CMake versions: ``` CMake Deprecation Warning at build/_deps/googletest-src/CMakeLists.txt:4 (cmake_minimum_required): Compatibility with CMake < 3.10 will be removed from a future version of CMake. ``` Updating to >= C++14 allows us to use GTest-1.15.2 which has a ``cmake_minimum_required(VERSION 3.13)`` --- .github/workflows/windows.yml | 5 +++-- CMakeLists.txt | 4 ++-- docs/source/install.rst | 4 ++-- test/unit/CMakeLists.txt | 4 +++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 59be3bdd84..902fed8c33 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -71,12 +71,13 @@ jobs: cd %PROJ_BUILD% set PROJ_DIR=%GITHUB_WORKSPACE%\proj_dir :: Not directly linked to BUILD_SHARED_LIBS, but a way to test different C++ standard versions - if "${{ env.BUILD_SHARED_LIBS }}"=="ON" (set EXTRA_CXX_FLAGS="/std:c++20") + if "${{ env.BUILD_SHARED_LIBS }}"=="ON" (set CMAKE_CXX_STANDARD="-DCMAKE_CXX_STANDARD=20") if "${{ env.BUILD_TYPE }}"=="Release" (set CMAKE_UNITY_BUILD_OPT="-DCMAKE_UNITY_BUILD=ON") cmake -D CMAKE_BUILD_TYPE="${{ env.BUILD_TYPE }}" ^ -D BUILD_SHARED_LIBS="${{ env.BUILD_SHARED_LIBS }}" ^ -D CMAKE_C_FLAGS="/WX" ^ - -D CMAKE_CXX_FLAGS="/WX %EXTRA_CXX_FLAGS%" ^ + -D CMAKE_CXX_FLAGS="/WX" ^ + %CMAKE_CXX_STANDARD% ^ -D CMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake ^ -D CMAKE_INSTALL_PREFIX="%PROJ_DIR%" ^ -D PROJ_DB_CACHE_DIR=%PROJ_DB_CACHE_DIR% ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index b6cf51b3ee..62aebc9979 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ cmake_policy(SET CMP0054 NEW) # Set C++ version # Make CMAKE_CXX_STANDARD available as cache option overridable by user -set(CMAKE_CXX_STANDARD 11 - CACHE STRING "C++ standard version to use (default is 11)") +set(CMAKE_CXX_STANDARD 17 + CACHE STRING "C++ standard version to use (default is 17)") message(STATUS "Requiring C++${CMAKE_CXX_STANDARD}") set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/docs/source/install.rst b/docs/source/install.rst index 8c5a95a4b0..e280159fdc 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -146,7 +146,7 @@ Build requirements ++++++++++++++++++ - C99 compiler -- C++11 compiler +- C++17 compiler - CMake >= 3.16 - SQLite3 >= 3.11: headers and library for target architecture, and sqlite3 executable for build architecture - libtiff >= 4.0 (optional but recommended) @@ -160,7 +160,7 @@ Test requirements These are only required if testing is built (see :option:`BUILD_TESTING`, default ON) -- GoogleTest (GTest) >= 1.8.1; if not found and :option:`TESTING_USE_NETWORK` is ON, then version 1.12.1 is fetched from GitHub and locally installed +- GoogleTest (GTest) >= 1.8.1; if not found and :option:`TESTING_USE_NETWORK` is ON, then version 1.15.2 is fetched from GitHub and locally installed - Python >= 3.7 - `importlib_metadata `_ only needed for Python 3.7 - One of either `PyYAML `_ or `ruamel.yaml `_ diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 860927fefd..09d0c5ef16 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -60,10 +60,12 @@ elseif(HAS_NETWORK) cmake_policy(SET CMP0135 NEW) # for DOWNLOAD_EXTRACT_TIMESTAMP option endif() + set(GTEST_VERSION "1.15.2") + include(FetchContent) FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip + URL https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.zip EXCLUDE_FROM_ALL # ignored before CMake 3.28 )