Skip to content

Commit 2ba6637

Browse files
committed
Map EPSG:1026 Mercator (Spherical) method to +proj=merc +R_C
1 parent d069819 commit 2ba6637

File tree

8 files changed

+160
-0
lines changed

8 files changed

+160
-0
lines changed

include/proj/coordinateoperation.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,11 @@ class PROJ_GCC_DLL Conversion : public SingleOperation {
12921292
const common::Angle &centerLong, const common::Length &falseEasting,
12931293
const common::Length &falseNorthing);
12941294

1295+
PROJ_DLL static ConversionNNPtr createMercatorSpherical(
1296+
const util::PropertyMap &properties, const common::Angle &centerLat,
1297+
const common::Angle &centerLong, const common::Length &falseEasting,
1298+
const common::Length &falseNorthing);
1299+
12951300
PROJ_DLL static ConversionNNPtr
12961301
createMollweide(const util::PropertyMap &properties,
12971302
const common::Angle &centerLong,

scripts/reference_exported_symbols.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ osgeo::proj::operation::Conversion::createLambertConicConformal_2SP_Michigan(osg
589589
osgeo::proj::operation::Conversion::createLambertConicConformal_2SP(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
590590
osgeo::proj::operation::Conversion::createLambertCylindricalEqualArea(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
591591
osgeo::proj::operation::Conversion::createLambertCylindricalEqualAreaSpherical(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
592+
osgeo::proj::operation::Conversion::createMercatorSpherical(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
592593
osgeo::proj::operation::Conversion::createMercatorVariantA(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Scale const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
593594
osgeo::proj::operation::Conversion::createMercatorVariantB(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
594595
osgeo::proj::operation::Conversion::createMillerCylindrical(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)

src/iso19111/io.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11180,7 +11180,26 @@ PROJStringParser::Private::buildProjectedCRS(int iStep,
1118011180
}
1118111181
}
1118211182
} else if (hasParamValue(step, "lat_ts")) {
11183+
if (hasParamValue(step, "R_C") &&
11184+
!geodCRS->ellipsoid()->isSphere() &&
11185+
getAngularValue(getParamValue(step, "lat_ts")) != 0) {
11186+
throw ParsingException("lat_ts != 0 not supported for "
11187+
"spherical Mercator on an ellipsoid");
11188+
}
1118311189
mapping = getMapping(EPSG_CODE_METHOD_MERCATOR_VARIANT_B);
11190+
} else if (hasParamValue(step, "R_C")) {
11191+
const auto &k = getParamValueK(step);
11192+
if (!k.empty() && getNumericValue(k) != 1.0) {
11193+
if (geodCRS->ellipsoid()->isSphere()) {
11194+
mapping = getMapping(EPSG_CODE_METHOD_MERCATOR_VARIANT_A);
11195+
} else {
11196+
throw ParsingException(
11197+
"k_0 != 1 not supported for spherical Mercator on an "
11198+
"ellipsoid");
11199+
}
11200+
} else {
11201+
mapping = getMapping(EPSG_CODE_METHOD_MERCATOR_SPHERICAL);
11202+
}
1118411203
} else {
1118511204
mapping = getMapping(EPSG_CODE_METHOD_MERCATOR_VARIANT_A);
1118611205
}

src/iso19111/operation/conversion.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,38 @@ ConversionNNPtr Conversion::createPopularVisualisationPseudoMercator(
17511751

17521752
// ---------------------------------------------------------------------------
17531753

1754+
/** \brief Instantiate a conversion based on the
1755+
* <a href="../../../operations/projections/merc.html">
1756+
* Mercator</a> projection method, using its spherical formulation
1757+
*
1758+
* When used with an ellipsoid, the radius used is the radius of the conformal
1759+
* sphere at centerLat.
1760+
*
1761+
* This method is defined as
1762+
* <a
1763+
* href="https://epsg.org/coord-operation-method_1026/Mercator-Spherical.html">
1764+
* EPSG:1026</a>.
1765+
*
1766+
* @param properties See \ref general_properties of the conversion. If the name
1767+
* is not provided, it is automatically set.
1768+
* @param centerLat See \ref center_latitude . Usually 0
1769+
* @param centerLong See \ref center_longitude . Usually 0
1770+
* @param falseEasting See \ref false_easting . Usually 0
1771+
* @param falseNorthing See \ref false_northing . Usually 0
1772+
* @return a new Conversion.
1773+
* @since 9.3
1774+
*/
1775+
ConversionNNPtr Conversion::createMercatorSpherical(
1776+
const util::PropertyMap &properties, const common::Angle &centerLat,
1777+
const common::Angle &centerLong, const common::Length &falseEasting,
1778+
const common::Length &falseNorthing) {
1779+
return create(
1780+
properties, EPSG_CODE_METHOD_MERCATOR_SPHERICAL,
1781+
createParams(centerLat, centerLong, falseEasting, falseNorthing));
1782+
}
1783+
1784+
// ---------------------------------------------------------------------------
1785+
17541786
/** \brief Instantiate a conversion based on the
17551787
* <a href="../../../operations/projections/moll.html">
17561788
* Mollweide</a> projection method.

src/iso19111/operation/parammappings.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,9 @@ static const MethodMapping projectionMethodMappings[] = {
770770
// handled manually
771771
"webmerc", nullptr, paramsNatOrigin},
772772

773+
{EPSG_NAME_METHOD_MERCATOR_SPHERICAL, EPSG_CODE_METHOD_MERCATOR_SPHERICAL,
774+
nullptr, "merc", "R_C", paramsNatOrigin},
775+
773776
{PROJ_WKT2_NAME_METHOD_MOLLWEIDE, 0, "Mollweide", "moll", nullptr,
774777
paramsLongNatOrigin},
775778

@@ -938,6 +941,7 @@ const struct MethodNameCode methodNameCodes[] = {
938941
METHOD_NAME_CODE(KROVAK),
939942
METHOD_NAME_CODE(LAMBERT_AZIMUTHAL_EQUAL_AREA),
940943
METHOD_NAME_CODE(POPULAR_VISUALISATION_PSEUDO_MERCATOR),
944+
METHOD_NAME_CODE(MERCATOR_SPHERICAL),
941945
METHOD_NAME_CODE(MERCATOR_VARIANT_A),
942946
METHOD_NAME_CODE(MERCATOR_VARIANT_B),
943947
METHOD_NAME_CODE(OBLIQUE_STEREOGRAPHIC),

src/proj_constants.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@
187187
"Popular Visualisation Pseudo Mercator"
188188
#define EPSG_CODE_METHOD_POPULAR_VISUALISATION_PSEUDO_MERCATOR 1024
189189

190+
#define EPSG_NAME_METHOD_MERCATOR_SPHERICAL "Mercator (Spherical)"
191+
#define EPSG_CODE_METHOD_MERCATOR_SPHERICAL 1026
192+
190193
#define PROJ_WKT2_NAME_METHOD_MOLLWEIDE "Mollweide"
191194

192195
#define PROJ_WKT2_NAME_METHOD_NATURAL_EARTH "Natural Earth"

test/unit/test_io.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10618,6 +10618,23 @@ TEST(io, projparse_cea_ellipsoidal_with_k_0) {
1061810618

1061910619
// ---------------------------------------------------------------------------
1062010620

10621+
TEST(io, projparse_merc_spherical_on_ellipsoid) {
10622+
std::string input("+proj=merc +R_C +lat_0=1 +lon_0=2 +x_0=3 +y_0=4 "
10623+
"+ellps=WGS84 +units=m +no_defs +type=crs");
10624+
auto obj = PROJStringParser().createFromPROJString(input);
10625+
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
10626+
ASSERT_TRUE(crs != nullptr);
10627+
EXPECT_EQ(crs->derivingConversion()->method()->getEPSGCode(),
10628+
EPSG_CODE_METHOD_MERCATOR_SPHERICAL);
10629+
EXPECT_EQ(
10630+
crs->exportToPROJString(
10631+
PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
10632+
.get()),
10633+
input);
10634+
}
10635+
10636+
// ---------------------------------------------------------------------------
10637+
1062110638
TEST(io, projparse_geos_sweep_x) {
1062210639
auto obj = PROJStringParser().createFromPROJString(
1062310640
"+proj=geos +sweep=x +h=1 +type=crs");

test/unit/test_operation.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3376,6 +3376,85 @@ TEST(operation, webmerc_import_from_broken_esri_WGS_84_Pseudo_Mercator) {
33763376

33773377
// ---------------------------------------------------------------------------
33783378

3379+
TEST(operation, mercator_spherical_export) {
3380+
auto conv = Conversion::createMercatorSpherical(
3381+
PropertyMap(), Angle(1), Angle(2), Length(3), Length(4));
3382+
EXPECT_TRUE(conv->validateParameters().empty());
3383+
3384+
EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()),
3385+
"+proj=merc +R_C +lat_0=1 +lon_0=2 +x_0=3 +y_0=4");
3386+
3387+
EXPECT_EQ(conv->exportToWKT(WKTFormatter::create().get()),
3388+
"CONVERSION[\"Mercator (Spherical)\",\n"
3389+
" METHOD[\"Mercator (Spherical)\",\n"
3390+
" ID[\"EPSG\",1026]],\n"
3391+
" PARAMETER[\"Latitude of natural origin\",1,\n"
3392+
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
3393+
" ID[\"EPSG\",8801]],\n"
3394+
" PARAMETER[\"Longitude of natural origin\",2,\n"
3395+
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
3396+
" ID[\"EPSG\",8802]],\n"
3397+
" PARAMETER[\"False easting\",3,\n"
3398+
" LENGTHUNIT[\"metre\",1],\n"
3399+
" ID[\"EPSG\",8806]],\n"
3400+
" PARAMETER[\"False northing\",4,\n"
3401+
" LENGTHUNIT[\"metre\",1],\n"
3402+
" ID[\"EPSG\",8807]]]");
3403+
}
3404+
3405+
// ---------------------------------------------------------------------------
3406+
3407+
TEST(operation, mercator_spherical_import) {
3408+
auto wkt2 = "PROJCRS[\"unknown\",\n"
3409+
" BASEGEOGCRS[\"unknown\",\n"
3410+
" DATUM[\"World Geodetic System 1984\",\n"
3411+
" ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
3412+
" LENGTHUNIT[\"metre\",1]],\n"
3413+
" ID[\"EPSG\",6326]],\n"
3414+
" PRIMEM[\"Greenwich\",0,\n"
3415+
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
3416+
" ID[\"EPSG\",8901]]],\n"
3417+
" CONVERSION[\"unknown\",\n"
3418+
" METHOD[\"Mercator (Spherical)\",\n"
3419+
" ID[\"EPSG\",1026]],\n"
3420+
" PARAMETER[\"Latitude of natural origin\",0,\n"
3421+
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
3422+
" ID[\"EPSG\",8801]],\n"
3423+
" PARAMETER[\"Longitude of natural origin\",0,\n"
3424+
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
3425+
" ID[\"EPSG\",8802]],\n"
3426+
" PARAMETER[\"False easting\",0,\n"
3427+
" LENGTHUNIT[\"metre\",1],\n"
3428+
" ID[\"EPSG\",8806]],\n"
3429+
" PARAMETER[\"False northing\",0,\n"
3430+
" LENGTHUNIT[\"metre\",1],\n"
3431+
" ID[\"EPSG\",8807]]],\n"
3432+
" CS[Cartesian,2],\n"
3433+
" AXIS[\"(E)\",east,\n"
3434+
" ORDER[1],\n"
3435+
" LENGTHUNIT[\"metre\",1,\n"
3436+
" ID[\"EPSG\",9001]]],\n"
3437+
" AXIS[\"(N)\",north,\n"
3438+
" ORDER[2],\n"
3439+
" LENGTHUNIT[\"metre\",1,\n"
3440+
" ID[\"EPSG\",9001]]]]";
3441+
3442+
auto obj = WKTParser().createFromWKT(wkt2);
3443+
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
3444+
ASSERT_TRUE(crs != nullptr);
3445+
3446+
EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()),
3447+
"+proj=merc +R_C +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 "
3448+
"+units=m +no_defs +type=crs");
3449+
3450+
EXPECT_EQ(
3451+
crs->exportToWKT(
3452+
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get()),
3453+
wkt2);
3454+
}
3455+
3456+
// ---------------------------------------------------------------------------
3457+
33793458
TEST(operation, mollweide_export) {
33803459

33813460
auto conv = Conversion::createMollweide(PropertyMap(), Angle(1), Length(2),

0 commit comments

Comments
 (0)