Skip to content

Commit

Permalink
Assorted set of fixes for PROJString to ISO19111 model:
Browse files Browse the repository at this point in the history
- createFromPROJString(): take into account axisswap step for Krovak and Transverse Mercator (South Orientated)
- Geocentric export to PROJ4: use datum when possible, and add explicit units=m
- ESRI WKT parser: make it case insensitive to parameter and projection names, and more tolerant about possible parameter name aliases
- import from WKT1 for Polar_Stereographic: don't be case sensitive
- importFromPROJString: allow pm to override datum
- Equidistant cylindrical: add support for non-standard latitude of natural origin, used in a GDAL test case
- tmerc export to PROJString: use 'k' instead of 'k_0'
- pj_ellps: use official value from EPSG for reverse flattening of Airy ellipsoid
- GDAL compatibility: add support for importing odd formulations of Mercator as WKT1, but rejecting them when exporting to PROJ
- Add export of 'Geostationary Satellite (Sweep X)' to WKT1_GDAL via EXTENSION.PROJ4 node
- importFromPROJString: add support for +f
- WKT1 / PROJ4: add support for EXTENSION.PROJ4 nodes and +wktext
- exportToWKT: change way we deal with AXIS by default for WKT1_GDAL
- Improve etmerc handling
- Fix WKT import of peg_point_heading for Spherical_Cross_Track_Height
- International Map of the World Polyconic: change parameter mapping
- exportToPROJ: add alpha parameter
- Hotine_Oblique_Mercator_Two_Point_Natural_Origin: GDAL_WKT1 related fix
- GDAL compatibility improvements in import from PROJ4 / WKT1 for polar stereographic
- Add support for +towgs84 when importing a +proj=geocent
- import from WKT1: add support for an odd Mercator_1SP formulation handled by GDAL
- export to proj4 strings: add +units=m to projected CRS for better GDAL compatibility
- export to proj4 strings: add +no_defs to CRS for better GDAL compatibility
  • Loading branch information
rouault committed Nov 19, 2018
1 parent 229bc49 commit cf54b0b
Show file tree
Hide file tree
Showing 17 changed files with 1,471 additions and 325 deletions.
3 changes: 2 additions & 1 deletion include/proj/coordinateoperation.hpp
Expand Up @@ -497,6 +497,7 @@ class PROJ_GCC_DLL OperationMethod : public common::IdentifiedObject {
PROJ_INTERNAL OperationMethod();
PROJ_INTERNAL OperationMethod(const OperationMethod &other);
INLINED_MAKE_SHARED
friend class Conversion;

private:
PROJ_OPAQUE_PRIVATE_DATA
Expand Down Expand Up @@ -1296,7 +1297,7 @@ class PROJ_GCC_DLL Conversion : public SingleOperation {
INLINED_MAKE_SHARED

PROJ_FRIEND(crs::ProjectedCRS);
PROJ_INTERNAL void addWKTExtensionNode(io::WKTFormatter *formatter) const;
PROJ_INTERNAL bool addWKTExtensionNode(io::WKTFormatter *formatter) const;

private:
PROJ_OPAQUE_PRIVATE_DATA
Expand Down
2 changes: 1 addition & 1 deletion include/proj/crs.hpp
Expand Up @@ -472,7 +472,7 @@ class PROJ_GCC_DLL DerivedCRS : virtual public SingleCRS {

PROJ_PRIVATE :
//! @cond Doxygen_Suppress
const operation::ConversionNNPtr &
PROJ_INTERNAL const operation::ConversionNNPtr &
derivingConversionRef() PROJ_CONST_DECL;
//! @endcond

Expand Down
37 changes: 21 additions & 16 deletions include/proj/internal/coordinateoperation_constants.hpp
Expand Up @@ -88,6 +88,11 @@ static const ParamMapping paramScaleFactor = {
EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, WKT1_SCALE_FACTOR,
common::UnitOfMeasure::Type::SCALE, k_0};

static const ParamMapping paramScaleFactorK = {
EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, WKT1_SCALE_FACTOR,
common::UnitOfMeasure::Type::SCALE, k};

static const ParamMapping paramFalseEasting = {
EPSG_NAME_PARAMETER_FALSE_EASTING, EPSG_CODE_PARAMETER_FALSE_EASTING,
WKT1_FALSE_EASTING, common::UnitOfMeasure::Type::LINEAR, x_0};
Expand Down Expand Up @@ -130,6 +135,10 @@ static const ParamMapping *const paramsNatOriginScale[] = {
&paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramScaleFactor,
&paramFalseEasting, &paramFalseNorthing, nullptr};

static const ParamMapping *const paramsNatOriginScaleK[] = {
&paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramScaleFactorK,
&paramFalseEasting, &paramFalseNorthing, nullptr};

static const ParamMapping paramLatFirstPoint = {
"Latitude of 1st point", 0, "Latitude_Of_1st_Point",
common::UnitOfMeasure::Type::ANGULAR, lat_1};
Expand Down Expand Up @@ -243,9 +252,11 @@ static const ParamMapping *const paramsEQDC[] = {&paramLatNatLatCenter,
static const ParamMapping *const paramsLonNatOrigin[] = {
&paramLongitudeNatOrigin, &paramFalseEasting, &paramFalseNorthing, nullptr};

static const ParamMapping *const paramsEqc[] = // same as paramsCEA
{&paramLat1stParallelLatTs, &paramLongitudeNatOrigin, &paramFalseEasting,
&paramFalseNorthing, nullptr};
static const ParamMapping *const paramsEqc[] = {
&paramLat1stParallelLatTs,
&paramLatitudeNatOrigin, // extension of EPSG, but used by GDAL / PROJ
&paramLongitudeNatOrigin, &paramFalseEasting,
&paramFalseNorthing, nullptr};

static const ParamMapping paramSatelliteHeight = {
"Satellite Height", 0, "satellite_height",
Expand Down Expand Up @@ -331,7 +342,7 @@ static const ParamMapping paramLonPoint2 = {
common::UnitOfMeasure::Type::ANGULAR, lon_2};

static const ParamMapping *const paramsHomTwoPoint[] = {
&paramLatCentreLatOrigin,
&paramLatCentreLatCenter,
&paramLatPoint1,
&paramLonPoint1,
&paramLatPoint2,
Expand All @@ -342,9 +353,8 @@ static const ParamMapping *const paramsHomTwoPoint[] = {
nullptr};

static const ParamMapping *const paramsIMWP[] = {
&paramLongitudeNatOrigin, &paramLatitude1stStdParallel,
&paramLatitude2ndStdParallel, &paramFalseEasting,
&paramFalseNorthing, nullptr};
&paramLongitudeNatOrigin, &paramLatFirstPoint, &paramLatSecondPoint,
&paramFalseEasting, &paramFalseNorthing, nullptr};

static const ParamMapping paramLonCentreLonCenter = {
EPSG_NAME_PARAMETER_LONGITUDE_OF_ORIGIN,
Expand All @@ -355,7 +365,7 @@ static const ParamMapping paramColatitudeConeAxis = {
EPSG_NAME_PARAMETER_COLATITUDE_CONE_AXIS,
EPSG_CODE_PARAMETER_COLATITUDE_CONE_AXIS, WKT1_AZIMUTH,
common::UnitOfMeasure::Type::ANGULAR,
nullptr}; /* ignored by PROJ currently */
"alpha"}; /* ignored by PROJ currently */

static const ParamMapping paramLatitudePseudoStdParallel = {
EPSG_NAME_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL,
Expand Down Expand Up @@ -393,11 +403,6 @@ static const ParamMapping paramLatMerc1SP = {
common::UnitOfMeasure::Type::ANGULAR,
nullptr}; // always set to zero, not to be exported in PROJ strings

static const ParamMapping paramScaleFactorK = {
EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, WKT1_SCALE_FACTOR,
common::UnitOfMeasure::Type::SCALE, k};

static const ParamMapping *const paramsMerc1SP[] = {
&paramLatMerc1SP, &paramLongitudeNatOrigin, &paramScaleFactorK,
&paramFalseEasting, &paramFalseNorthing, nullptr};
Expand Down Expand Up @@ -492,12 +497,12 @@ static const ParamMapping *const paramsLabordeObliqueMercator[] = {

static const MethodMapping methodMappings[] = {
{EPSG_NAME_METHOD_TRANSVERSE_MERCATOR, EPSG_CODE_METHOD_TRANSVERSE_MERCATOR,
"Transverse_Mercator", "tmerc", nullptr, paramsNatOriginScale},
"Transverse_Mercator", "tmerc", nullptr, paramsNatOriginScaleK},

{EPSG_NAME_METHOD_TRANSVERSE_MERCATOR_SOUTH_ORIENTATED,
EPSG_CODE_METHOD_TRANSVERSE_MERCATOR_SOUTH_ORIENTATED,
"Transverse_Mercator_South_Orientated", "tmerc", "axis=wsu",
paramsNatOriginScale},
paramsNatOriginScaleK},

{PROJ_WKT2_NAME_METHOD_TWO_POINT_EQUIDISTANT, 0, "Two_Point_Equidistant",
"tpeqd", nullptr, paramsTPEQD},
Expand Down Expand Up @@ -605,7 +610,7 @@ static const MethodMapping methodMappings[] = {
{PROJ_WKT2_NAME_METHOD_INTERRUPTED_GOODE_HOMOLOSINE, 0,
"Interrupted_Goode_Homolosine", "igh", nullptr, paramsLonNatOrigin},

// No WKT1 representation fr sweep=x
// No proper WKT1 representation fr sweep=x
{PROJ_WKT2_NAME_METHOD_GEOSTATIONARY_SATELLITE_SWEEP_X, 0, nullptr, "geos",
"sweep=x", paramsGeos},

Expand Down
2 changes: 2 additions & 0 deletions include/proj/internal/coordinateoperation_internal.hpp
Expand Up @@ -70,6 +70,8 @@ const ParamMapping *getMapping(const MethodMapping *mapping,
const OperationParameterValue *param);
const ParamMapping *getMappingFromWKT1(const MethodMapping *mapping,
const std::string &wkt1_name);
bool areEquivalentParameters(const std::string &a, const std::string &b);

// ---------------------------------------------------------------------------

struct ESRIParamMapping {
Expand Down
2 changes: 2 additions & 0 deletions include/proj/internal/internal.hpp
Expand Up @@ -125,6 +125,8 @@ inline bool starts_with(const std::string &str, const char *prefix) noexcept {
return std::memcmp(str.c_str(), prefix, prefixSize) == 0;
}

bool ci_less(const std::string &a, const std::string &b) noexcept;

bool ci_starts_with(const char *str, const char *prefix) noexcept;

bool ci_starts_with(const std::string &str, const std::string &prefix) noexcept;
Expand Down
23 changes: 20 additions & 3 deletions include/proj/io.hpp
Expand Up @@ -206,7 +206,19 @@ class PROJ_GCC_DLL WKTFormatter {

PROJ_DLL WKTFormatter &setMultiLine(bool multiLine) noexcept;
PROJ_DLL WKTFormatter &setIndentationWidth(int width) noexcept;
PROJ_DLL WKTFormatter &setOutputAxis(bool outputAxis) noexcept;

/** Rule for output AXIS nodes */
enum class OutputAxisRule {
/** Always include AXIS nodes */
YES,
/** Never include AXIS nodes */
NO,
/** Includes them only on PROJCS node if it uses Easting/Northing
*ordering. Typically used for WKT1_GDAL */
WKT1_GDAL_EPSG_STYLE,
};

PROJ_DLL WKTFormatter &setOutputAxis(OutputAxisRule outputAxis) noexcept;
PROJ_DLL WKTFormatter &setStrict(bool strict) noexcept;
PROJ_DLL bool isStrict() const noexcept;

Expand Down Expand Up @@ -273,7 +285,7 @@ class PROJ_GCC_DLL WKTFormatter {
PROJ_INTERNAL bool isInverted() const;
#endif

PROJ_INTERNAL bool outputAxis() const;
PROJ_INTERNAL OutputAxisRule outputAxis() const;
PROJ_INTERNAL bool outputAxisOrder() const;
PROJ_INTERNAL bool primeMeridianOmittedIfGreenwich() const;
PROJ_INTERNAL bool ellipsoidUnitOmittedIfMetre() const;
Expand Down Expand Up @@ -352,7 +364,7 @@ class PROJ_GCC_DLL PROJStringFormatter {
startInversion();
PROJ_DLL void stopInversion();
PROJ_INTERNAL bool isInverted() const;
PROJ_INTERNAL bool getUseETMercForTMerc() const;
PROJ_INTERNAL bool getUseETMercForTMerc(bool &settingSetOut) const;

PROJ_DLL void
ingestPROJString(const std::string &str); // throw ParsingException
Expand All @@ -373,6 +385,11 @@ class PROJ_GCC_DLL PROJStringFormatter {
PROJ_DLL void addParam(const char *paramName,
const std::vector<double> &vals);

PROJ_INTERNAL bool hasParam(const char *paramName) const;

PROJ_INTERNAL void addNoDefs(bool b);
PROJ_INTERNAL bool getAddNoDefs() const;

PROJ_INTERNAL std::set<std::string> getUsedGridNames() const;

PROJ_INTERNAL void setTOWGS84Parameters(const std::vector<double> &params);
Expand Down
17 changes: 14 additions & 3 deletions src/c_api.cpp
Expand Up @@ -839,7 +839,10 @@ static const char *getOptionValue(const char *option,
* <li>MULTILINE=YES/NO. Defaults to YES, except for WKT1_ESRI</li>
* <li>INDENTATION_WIDTH=number. Defauls to 4 (when multiline output is
* on).</li>
* <li>OUTPUT_AXIS=YES/NO. Defaults to YES, except for WKT1_ESRI.</li>
* <li>OUTPUT_AXIS=AUTO/YES/NO. In AUTO mode, axis will be output for WKT2
* variants, for WKT1_GDAL for ProjectedCRS with easting/northing ordering
* (otherwise stripped), but not for WKT1_ESRI. Setting to YES will output
* them unconditionaly, and to NO will omit them unconditionaly.</li>
* </ul>
* @return a string, or NULL in case of error.
*/
Expand Down Expand Up @@ -890,7 +893,12 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type,
} else if ((value = getOptionValue(*iter, "INDENTATION_WIDTH="))) {
formatter->setIndentationWidth(std::atoi(value));
} else if ((value = getOptionValue(*iter, "OUTPUT_AXIS="))) {
formatter->setOutputAxis(ci_equal(value, "YES"));
if (!ci_equal(value, "AUTO")) {
formatter->setOutputAxis(
ci_equal(value, "YES")
? WKTFormatter::OutputAxisRule::YES
: WKTFormatter::OutputAxisRule::NO);
}
} else {
std::string msg("Unknown option :");
msg += *iter;
Expand Down Expand Up @@ -925,7 +933,8 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type,
* @param options NULL-terminated list of strings with "KEY=VALUE" format. or
* NULL.
* The currently recognized option is USE_ETMERC=YES to use
* +proj=etmerc instead of +proj=tmerc
* +proj=etmerc instead of +proj=tmerc (or USE_ETMERC=NO to disable implicit
* use of etmerc by utm conversions)
* @return a string, or NULL in case of error.
*/
const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type,
Expand Down Expand Up @@ -960,6 +969,8 @@ const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type,
if (options != nullptr && options[0] != nullptr) {
if (ci_equal(options[0], "USE_ETMERC=YES")) {
formatter->setUseETMercForTMerc(true);
} else if (ci_equal(options[0], "USE_ETMERC=NO")) {
formatter->setUseETMercForTMerc(false);
}
}
obj->lastPROJString = exportable->exportToPROJString(formatter.get());
Expand Down

0 comments on commit cf54b0b

Please sign in to comment.