aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/plot/plotdefs.json8
-rw-r--r--docs/source/operations/projections/peirce_q.rst28
-rw-r--r--scripts/build_esri_projection_mapping.py19
-rw-r--r--src/iso19111/io.cpp2
-rw-r--r--src/iso19111/operation/conversion.cpp24
-rw-r--r--src/iso19111/operation/esriparammappings.cpp31
-rw-r--r--src/iso19111/operation/parammappings.cpp6
-rw-r--r--src/proj_constants.h3
-rw-r--r--src/projections/adams.cpp139
-rw-r--r--test/gie/peirce_q.gie342
-rw-r--r--test/unit/test_io.cpp75
11 files changed, 626 insertions, 51 deletions
diff --git a/docs/plot/plotdefs.json b/docs/plot/plotdefs.json
index a6d70273..f55f5e0a 100644
--- a/docs/plot/plotdefs.json
+++ b/docs/plot/plotdefs.json
@@ -1057,7 +1057,7 @@
"lonmax": 180,
"lonmin": -180,
"name": "peirce_q_square",
- "projstring": "+proj=peirce_q +lon_0=25 +type=square",
+ "projstring": "+proj=peirce_q +lon_0=25 +shape=square",
"res": "low",
"type": "poly"
},
@@ -1068,7 +1068,7 @@
"lonmax": 180,
"lonmin": -180,
"name": "peirce_q",
- "projstring": "+proj=peirce_q +lon_0=25 +type=diamond",
+ "projstring": "+proj=peirce_q +lon_0=25 +shape=diamond",
"res": "low",
"type": "poly"
},
@@ -1079,7 +1079,7 @@
"lonmax": 180,
"lonmin": -180,
"name": "peirce_q_horizontal",
- "projstring": "+proj=peirce_q +lon_0=25 +type=horizontal",
+ "projstring": "+proj=peirce_q +lon_0=25 +shape=horizontal",
"res": "low",
"type": "line"
},
@@ -1090,7 +1090,7 @@
"lonmax": 180,
"lonmin": -180,
"name": "grieger_triptychial",
- "projstring": "+proj=pipeline +step +proj=ob_tran +o_proj=peirce_q +o_lat_p=-45 +o_lon_p=45 +type=horizontal +scrollx=-0.25 +step +proj=affine +s11=-1 +s12=0 +s21=0 +s22=-1",
+ "projstring": "+proj=pipeline +step +proj=ob_tran +o_proj=peirce_q +o_lat_p=-45 +o_lon_p=45 +shape=horizontal +scrollx=-0.25 +step +proj=affine +s11=-1 +s12=0 +s21=0 +s22=-1",
"res": "low",
"type": "poly"
},
diff --git a/docs/source/operations/projections/peirce_q.rst b/docs/source/operations/projections/peirce_q.rst
index cf972932..57504032 100644
--- a/docs/source/operations/projections/peirce_q.rst
+++ b/docs/source/operations/projections/peirce_q.rst
@@ -14,10 +14,10 @@ defaults to a central meridian of 0, it is more common to use a central
meridian of around 25 to optimise the distortions. Peirce's original
published map from 1879 used a central meridian of approx -70.
The diamond and square versions can be produced using the
-``+type=diamond`` and ``+type=square`` options respectively.
+``+shape=diamond`` and ``+shape=square`` options respectively.
This implementation includes an alternative lateral projection
-which places hemispheres side-by-side (``+type=horizontal`` or
-``+type=vertical``). Combined with a general oblique transformation,
+which places hemispheres side-by-side (``+shape=horizontal`` or
+``+shape=vertical``). Combined with a general oblique transformation,
this can be used to produced a Grieger Triptychial projection
(see example below).
@@ -43,21 +43,21 @@ this can be used to produced a Grieger Triptychial projection
:align: center
:alt: Peirce Quincuncial (Square)
- proj-string: ``+proj=peirce_q +lon_0=25 +type=square``
+ proj-string: ``+proj=peirce_q +lon_0=25 +shape=square``
.. figure:: ./images/peirce_q_diamond.png
:width: 500 px
:align: center
:alt: Peirce Quincuncial (Diamond)
- proj-string: ``+proj=peirce_q +lon_0=25 +type=diamond``
+ proj-string: ``+proj=peirce_q +lon_0=25 +shape=diamond``
.. figure:: ./images/peirce_q_horizontal.png
:width: 500 px
:align: center
:alt: Peirce Quincuncial (Horizontal)
- proj-string: ``+proj=peirce_q +lon_0=25 +type=horizontal``
+ proj-string: ``+proj=peirce_q +lon_0=25 +shape=horizontal``
.. figure:: ./images/grieger_triptychial.png
:width: 500 px
@@ -73,16 +73,20 @@ Parameters
.. include:: ../options/lon_0.rst
-.. option:: +type=square/diamond/horizontal/vertical/nhemisphere/shemisphere
+.. option:: +shape=square/diamond/horizontal/vertical/nhemisphere/shemisphere
- .. versionadded:: 8.2.1
+ .. versionadded:: 9.0
*Defaults to diamond.*
- Indicates the type of transformation applied to the southern hemisphere:
+ .. warning:: This option was wrongly introduced introduced in 8.2.1 with the
+ ``type`` name, which was inappropriate as it conflicted with
+ the ``+type=crs`` general hint.
+
+ Indicates the shape of transformation applied to the southern hemisphere:
``square`` and ``diamond`` represent the traditional quincuncial form suggested
by Peirce with the southern hemisphere divided into 4 triangles and reflected
- outward from the northern hemisphere. The ``square`` type is rotated by 45
+ outward from the northern hemisphere. The ``square`` shape is rotated by 45
degrees to produce the conventional square presentation. The origin lies at
the centre of the square or diamond.
@@ -96,14 +100,14 @@ Parameters
.. option:: +scrollx=<value>
- For ``horizontal`` type allows a scalar circular scroll of resulting x coordinates
+ For ``horizontal`` shape allows a scalar circular scroll of resulting x coordinates
to shift sections of the projection to the other horizontal side of the map.
*Defaults to 0.0. Must be a scale between -1.0 and 1.0.*
.. option:: +scrolly=<value>
- For ``vertical`` type allows a scalar circular scroll of resulting y coordinates
+ For ``vertical`` shape allows a scalar circular scroll of resulting y coordinates
to shift sections of the projection to the other vertical side of the map.
*Defaults to 0.0. Must be a scale between -1.0 and 1.0.*
diff --git a/scripts/build_esri_projection_mapping.py b/scripts/build_esri_projection_mapping.py
index 30f4ad6c..32920a59 100644
--- a/scripts/build_esri_projection_mapping.py
+++ b/scripts/build_esri_projection_mapping.py
@@ -710,6 +710,24 @@ config_str = """
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
+- Peirce_Quincuncial:
+ - WKT2_name: PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_SQUARE
+ Params:
+ - False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
+ - False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
+ - Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
+ - Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
+ - Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
+ - Option: 0.0
+
+ - WKT2_name: PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_DIAMOND
+ Params:
+ - False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
+ - False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
+ - Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
+ - Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
+ - Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
+ - Option: 1.0
# Missing/unclear mappings
@@ -748,7 +766,6 @@ config_str = """
# Polar_Stereographic_Variant_C
# Quartic_Authalic_Ellipsoidal
# Adams_Square_II
-# Peirce_Quincuncial
"""
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index ca5a3d97..fc92dbbd 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -10209,6 +10209,8 @@ PROJStringParser::Private::buildProjectedCRS(int iStep,
}
} else if (param->unit_type == UnitOfMeasure::Type::SCALE) {
value = 1;
+ } else if (step.name == "peirce_q" && proj_name == "lat_0") {
+ value = 90;
}
PropertyMap propertiesParameter;
diff --git a/src/iso19111/operation/conversion.cpp b/src/iso19111/operation/conversion.cpp
index 77e703f3..6bccf182 100644
--- a/src/iso19111/operation/conversion.cpp
+++ b/src/iso19111/operation/conversion.cpp
@@ -3839,6 +3839,30 @@ void Conversion::_exportToPROJString(
formatter->addParam("x_0", falseEasting);
formatter->addParam("y_0", falseNorthing);
bConversionDone = true;
+ } else if (ci_equal(methodName,
+ PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_SQUARE) ||
+ ci_equal(methodName,
+ PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_DIAMOND)) {
+ const auto &scaleFactor = parameterValueMeasure(
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN);
+ if (scaleFactor.unit().type() != common::UnitOfMeasure::Type::UNKNOWN &&
+ std::fabs(scaleFactor.getSIValue() - 1.0) > 1e-10) {
+ throw io::FormattingException(
+ "Only scale factor = 1 handled for Peirce Quincuncial");
+ }
+ const double latitudeOfOriginDeg =
+ parameterValue(EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN)
+ ->value()
+ .unit()
+ .type() != common::UnitOfMeasure::Type::UNKNOWN
+ ? parameterValueNumeric(
+ EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
+ common::UnitOfMeasure::DEGREE)
+ : 90.0;
+ if (std::fabs(latitudeOfOriginDeg - 90.0) > 1e-10) {
+ throw io::FormattingException("Only latitude of natural origin = "
+ "90 handled for Peirce Quincuncial");
+ }
} else if (formatter->convention() ==
io::PROJStringFormatter::Convention::PROJ_5 &&
isZUnitConversion) {
diff --git a/src/iso19111/operation/esriparammappings.cpp b/src/iso19111/operation/esriparammappings.cpp
index 8021b95f..a6f6c6a1 100644
--- a/src/iso19111/operation/esriparammappings.cpp
+++ b/src/iso19111/operation/esriparammappings.cpp
@@ -947,6 +947,33 @@ static const ESRIParamMapping paramsESRI_Equal_Earth[] = {
EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};
+static const ESRIParamMapping paramsESRI_Peirce_Quincuncial_alt1[] = {
+ {"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
+ EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
+ {"False_Northing", EPSG_NAME_PARAMETER_FALSE_NORTHING,
+ EPSG_CODE_PARAMETER_FALSE_NORTHING, "0.0", false},
+ {"Central_Meridian", EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
+ {"Scale_Factor", EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, "0.0", false},
+ {"Latitude_Of_Origin", EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
+ {"Option", nullptr, 0, "0.0", false},
+ {nullptr, nullptr, 0, "0.0", false}};
+static const ESRIParamMapping paramsESRI_Peirce_Quincuncial_alt2[] = {
+ {"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
+ EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
+ {"False_Northing", EPSG_NAME_PARAMETER_FALSE_NORTHING,
+ EPSG_CODE_PARAMETER_FALSE_NORTHING, "0.0", false},
+ {"Central_Meridian", EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
+ {"Scale_Factor", EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, "0.0", false},
+ {"Latitude_Of_Origin", EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
+ EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
+ {"Option", nullptr, 0, "1.0", false},
+ {nullptr, nullptr, 0, "0.0", false}};
+
static const ESRIMethodMapping esriMappings[] = {
{"Plate_Carree", EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL,
EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL, paramsESRI_Plate_Carree},
@@ -1115,6 +1142,10 @@ static const ESRIMethodMapping esriMappings[] = {
EPSG_CODE_METHOD_COLOMBIA_URBAN, paramsESRI_IGAC_Plano_Cartesiano},
{"Equal_Earth", EPSG_NAME_METHOD_EQUAL_EARTH, EPSG_CODE_METHOD_EQUAL_EARTH,
paramsESRI_Equal_Earth},
+ {"Peirce_Quincuncial", PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_SQUARE, 0,
+ paramsESRI_Peirce_Quincuncial_alt1},
+ {"Peirce_Quincuncial", PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_DIAMOND, 0,
+ paramsESRI_Peirce_Quincuncial_alt2},
};
// ---------------------------------------------------------------------------
diff --git a/src/iso19111/operation/parammappings.cpp b/src/iso19111/operation/parammappings.cpp
index af1309b3..dd94e267 100644
--- a/src/iso19111/operation/parammappings.cpp
+++ b/src/iso19111/operation/parammappings.cpp
@@ -793,6 +793,12 @@ static const MethodMapping projectionMethodMappings[] = {
{PROJ_WKT2_NAME_METHOD_ROBINSON, 0, "Robinson", "robin", nullptr,
paramsLonNatOriginLongitudeCentre},
+ {PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_SQUARE, 0, nullptr, "peirce_q",
+ "shape=square", paramsNatOriginScale},
+
+ {PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_DIAMOND, 0, nullptr, "peirce_q",
+ "shape=diamond", paramsNatOriginScale},
+
{PROJ_WKT2_NAME_METHOD_SINUSOIDAL, 0, "Sinusoidal", "sinu", nullptr,
paramsLonNatOriginLongitudeCentre},
diff --git a/src/proj_constants.h b/src/proj_constants.h
index 815511fe..1da63474 100644
--- a/src/proj_constants.h
+++ b/src/proj_constants.h
@@ -248,6 +248,9 @@
#define EPSG_CODE_METHOD_COLOMBIA_URBAN 1052
#define EPSG_NAME_METHOD_COLOMBIA_URBAN "Colombia Urban"
+#define PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_SQUARE "Peirce Quincuncial (Square)"
+#define PROJ_WKT2_NAME_METHOD_PEIRCE_QUINCUNCIAL_DIAMOND "Peirce Quincuncial (Diamond)"
+
/* ------------------------------------------------------------------------ */
/* Projection parameters */
diff --git a/src/projections/adams.cpp b/src/projections/adams.cpp
index 4150fff2..b0c2849c 100644
--- a/src/projections/adams.cpp
+++ b/src/projections/adams.cpp
@@ -60,7 +60,7 @@ enum projection_type {
ADAMS_WS2,
};
-enum peirce_type {
+enum peirce_shape {
PEIRCE_Q_SQUARE,
PEIRCE_Q_DIAMOND,
PEIRCE_Q_NHEMISPHERE,
@@ -71,7 +71,7 @@ enum peirce_type {
struct pj_opaque {
projection_type mode;
- peirce_type pqtype;
+ peirce_shape pqshape;
double scrollx = 0.0;
double scrolly = 0.0;
};
@@ -143,13 +143,13 @@ static PJ_XY adams_forward(PJ_LP lp, PJ *P) {
break;
case PEIRCE_Q: {
/* lam0 - note that the original Peirce model used a central meridian of around -70deg, but the default within proj is +lon0=0 */
- if (Q->pqtype == PEIRCE_Q_NHEMISPHERE) {
+ if (Q->pqshape == PEIRCE_Q_NHEMISPHERE) {
if( lp.phi < -TOL ) {
proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
return proj_coord_error().xy;
}
}
- if (Q->pqtype == PEIRCE_Q_SHEMISPHERE) {
+ if (Q->pqshape == PEIRCE_Q_SHEMISPHERE) {
if( lp.phi > -TOL ) {
proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
return proj_coord_error().xy;
@@ -211,7 +211,7 @@ static PJ_XY adams_forward(PJ_LP lp, PJ *P) {
constexpr double shd = 1.8540746773013719 * 2;
/* For square and diamond Quincuncial projections, spin out southern hemisphere to triangular segments of quincunx (before rotation for square)*/
- if( Q->pqtype == PEIRCE_Q_SQUARE || ( Q->pqtype == PEIRCE_Q_DIAMOND )) {
+ if( Q->pqshape == PEIRCE_Q_SQUARE || ( Q->pqshape == PEIRCE_Q_DIAMOND )) {
if (lp.phi < 0.) { /* fold out segments */
if (lp.lam < ( -0.75 * M_PI )) xy.y = shd - xy.y; /* top left segment, shift up and reflect y */
if ( (lp.lam < (-0.25 * M_PI)) && (lp.lam >= ( -0.75 * M_PI ))) xy.x = - shd - xy.x; /* left segment, shift left and reflect x */
@@ -222,20 +222,20 @@ static PJ_XY adams_forward(PJ_LP lp, PJ *P) {
}
/* For square types rotate xy by 45 deg */
- if( Q->pqtype == PEIRCE_Q_SQUARE ) {
+ if( Q->pqshape == PEIRCE_Q_SQUARE ) {
const double temp = xy.x;
xy.x = RSQRT2 * (xy.x - xy.y);
xy.y = RSQRT2 * (temp + xy.y);
}
/* For rectangle Quincuncial projs, spin out southern hemisphere to east (horizontal) or north (vertical) after rotation */
- if( Q->pqtype == PEIRCE_Q_HORIZONTAL ) {
+ if( Q->pqshape == PEIRCE_Q_HORIZONTAL ) {
if (lp.phi < 0.) {
xy.x = shd - xy.x; /* reflect x to east */
}
xy.x = xy.x - (shd / 2); /* shift everything so origin is in middle of two hemispheres */
}
- if( Q->pqtype == PEIRCE_Q_VERTICAL ) {
+ if( Q->pqshape == PEIRCE_Q_VERTICAL ) {
if (lp.phi < 0.) {
xy.y = shd - xy.y; /* reflect y to north */
}
@@ -243,7 +243,7 @@ static PJ_XY adams_forward(PJ_LP lp, PJ *P) {
}
//if o_scrollx param present, scroll x
- if (!(Q->scrollx == 0.0) && (Q->pqtype == PEIRCE_Q_HORIZONTAL) ) {
+ if (!(Q->scrollx == 0.0) && (Q->pqshape == PEIRCE_Q_HORIZONTAL) ) {
double xscale = 2.0;
double xthresh = shd / 2;
xy.x = xy.x + (Q->scrollx * (xthresh * 2 * xscale)); /*shift relative to proj width*/
@@ -256,7 +256,7 @@ static PJ_XY adams_forward(PJ_LP lp, PJ *P) {
}
//if o_scrolly param present, scroll y
- if (!(Q->scrolly == 0.0) && (Q->pqtype == PEIRCE_Q_VERTICAL)) {
+ if (!(Q->scrolly == 0.0) && (Q->pqshape == PEIRCE_Q_VERTICAL)) {
double yscale = 2.0;
double ythresh = shd / 2;
xy.y = xy.y + (Q->scrolly * (ythresh * 2 * yscale)); /*shift relative to proj height*/
@@ -299,6 +299,91 @@ static PJ_LP adams_inverse(PJ_XY xy, PJ *P)
return pj_generic_inverse_2d(xy, P, lp);
}
+static PJ_LP peirce_q_square_inverse(PJ_XY xy, PJ *P)
+{
+ /* Heuristics based on trial and repeat process */
+ PJ_LP lp;
+ lp.phi = 0;
+ if( xy.x == 0 && xy.y < 0 )
+ {
+ lp.lam = -M_PI / 4;
+ if( fabs(xy.y) < 2.622057580396 )
+ lp.phi = M_PI / 4;
+ }
+ else if( xy.x > 0 && fabs(xy.y) < 1e-7 )
+ lp.lam = M_PI / 4;
+ else if( xy.x < 0 && fabs(xy.y) < 1e-7 )
+ {
+ lp.lam = -3 * M_PI / 4;
+ lp.phi = M_PI / 2 / 2.622057574224 * xy.x + M_PI / 2;
+ }
+ else if( fabs(xy.x) < 1e-7 && xy.y > 0 )
+ lp.lam = 3 * M_PI / 4;
+ else if( xy.x >= 0 && xy.y <= 0 )
+ {
+ lp.lam = 0;
+ if( xy.x == 0 && xy.y == 0 )
+ {
+ lp.phi = M_PI / 2;
+ return lp;
+ }
+ }
+ else if( xy.x >= 0 && xy.y >= 0 )
+ lp.lam = M_PI / 2;
+ else if( xy.x <= 0 && xy.y >= 0 )
+ {
+ if( fabs(xy.x) < fabs(xy.y) )
+ lp.lam = M_PI * 0.9;
+ else
+ lp.lam = -M_PI * 0.9;
+ }
+ else /* if( xy.x <= 0 && xy.y <= 0 ) */
+ lp.lam = -M_PI / 2;
+ return pj_generic_inverse_2d(xy, P, lp);
+}
+
+static PJ_LP peirce_q_diamond_inverse(PJ_XY xy, PJ *P)
+{
+ /* Heuristics based on a trial and repeat process */
+ PJ_LP lp;
+ lp.phi = 0;
+ if( xy.x >= 0 && xy.y <= 0 )
+ {
+ lp.lam = M_PI / 4;
+ if( xy.x > 0 && xy.y == 0 )
+ {
+ lp.lam = M_PI / 2;
+ lp.phi = 0;
+ }
+ else if( xy.x == 0 && xy.y == 0 )
+ {
+ lp.lam = 0;
+ lp.phi = M_PI / 2;
+ return lp;
+ }
+ else if( xy.x == 0 && xy.y < 0 )
+ {
+ lp.lam = 0;
+ lp.phi = M_PI / 4;
+ }
+ }
+ else if( xy.x >= 0 && xy.y >= 0 )
+ lp.lam = 3 * M_PI / 4;
+ else if( xy.x <= 0 && xy.y >= 0 )
+ {
+ lp.lam = -3 * M_PI / 4;
+ }
+ else /* if( xy.x <= 0 && xy.y <= 0 ) */
+ lp.lam = -M_PI / 4;
+
+ if( fabs(xy.x) > 1.8540746773013719 + 1e-3 ||
+ fabs(xy.y) > 1.8540746773013719 + 1e-3 )
+ {
+ lp.phi = -M_PI / 4;
+ }
+
+ return pj_generic_inverse_2d(xy, P, lp);
+}
static PJ *setup(PJ *P, projection_type mode) {
struct pj_opaque *Q = static_cast<struct pj_opaque*>(
@@ -316,25 +401,27 @@ static PJ *setup(PJ *P, projection_type mode) {
P->inv = adams_inverse;
if( mode == PEIRCE_Q) {
- // Quincuncial projections type options: square, diamond, hemisphere, horizontal (rectangle) or vertical (rectangle)
- const char* pqtype = pj_param (P->ctx, P->params, "stype").s;
+ // Quincuncial projections shape options: square, diamond, hemisphere, horizontal (rectangle) or vertical (rectangle)
+ const char* pqshape = pj_param (P->ctx, P->params, "sshape").s;
- if (!pqtype) pqtype = "diamond"; /* default if type value not supplied */
+ if (!pqshape) pqshape = "diamond"; /* default if shape value not supplied */
- if (strcmp(pqtype, "square") == 0) {
- Q->pqtype = PEIRCE_Q_SQUARE;
+ if (strcmp(pqshape, "square") == 0) {
+ Q->pqshape = PEIRCE_Q_SQUARE;
+ P->inv = peirce_q_square_inverse;
}
- else if (strcmp(pqtype, "diamond") == 0) {
- Q->pqtype = PEIRCE_Q_DIAMOND;
+ else if (strcmp(pqshape, "diamond") == 0) {
+ Q->pqshape = PEIRCE_Q_DIAMOND;
+ P->inv = peirce_q_diamond_inverse;
}
- else if (strcmp(pqtype, "nhemisphere") == 0) {
- Q->pqtype = PEIRCE_Q_NHEMISPHERE;
+ else if (strcmp(pqshape, "nhemisphere") == 0) {
+ Q->pqshape = PEIRCE_Q_NHEMISPHERE;
}
- else if (strcmp(pqtype, "shemisphere") == 0) {
- Q->pqtype = PEIRCE_Q_SHEMISPHERE;
+ else if (strcmp(pqshape, "shemisphere") == 0) {
+ Q->pqshape = PEIRCE_Q_SHEMISPHERE;
}
- else if (strcmp(pqtype, "horizontal") == 0) {
- Q->pqtype = PEIRCE_Q_HORIZONTAL;
+ else if (strcmp(pqshape, "horizontal") == 0) {
+ Q->pqshape = PEIRCE_Q_HORIZONTAL;
if (pj_param(P->ctx, P->params, "tscrollx").i) {
double scrollx;
scrollx = pj_param(P->ctx, P->params, "dscrollx").f;
@@ -345,8 +432,8 @@ static PJ *setup(PJ *P, projection_type mode) {
Q->scrollx = scrollx;
}
}
- else if (strcmp(pqtype, "vertical") == 0) {
- Q->pqtype = PEIRCE_Q_VERTICAL;
+ else if (strcmp(pqshape, "vertical") == 0) {
+ Q->pqshape = PEIRCE_Q_VERTICAL;
if (pj_param(P->ctx, P->params, "tscrolly").i) {
double scrolly;
scrolly = pj_param(P->ctx, P->params, "dscrolly").f;
@@ -358,7 +445,7 @@ static PJ *setup(PJ *P, projection_type mode) {
}
}
else {
- proj_log_error (P, _("peirce_q: invalid value for 'type' parameter"));
+ proj_log_error (P, _("peirce_q: invalid value for 'shape' parameter"));
return pj_default_destructor (P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
}
diff --git a/test/gie/peirce_q.gie b/test/gie/peirce_q.gie
index 713d2581..777ce054 100644
--- a/test/gie/peirce_q.gie
+++ b/test/gie/peirce_q.gie
@@ -14,7 +14,7 @@
------------------------------------------------------------
------------------------------------------------------------
-operation +proj=peirce_q +R=6370997 +type=square
+operation +proj=peirce_q +R=6370997 +shape=square
tolerance 10 mm
------------------------------------------------------------
@@ -138,7 +138,7 @@ accept 170.3972098164 87.6222109978
expect -153172.25 215556.52
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=diamond
+ operation +proj=peirce_q +R=6370997 +shape=diamond
tolerance 10 mm
------------------------------------------------------------
@@ -262,7 +262,7 @@ accept 170.3972098164 87.6222109978
expect 44112.34 260730.62
------------------------------------------------------------
-operation +proj=peirce_q +R=6370997 +type=horizontal
+operation +proj=peirce_q +R=6370997 +shape=horizontal
tolerance 10 mm
------------------------------------------------------------
@@ -386,7 +386,7 @@ accept 170.3972098164 87.6222109978
expect -11768191.87 260730.62
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=horizontal +scrollx=0.75
+ operation +proj=peirce_q +R=6370997 +shape=horizontal +scrollx=0.75
tolerance 10 mm
------------------------------------------------------------
@@ -510,7 +510,7 @@ accept 170.3972098164 87.6222109978
expect -23580496.07 260730.62
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=vertical
+ operation +proj=peirce_q +R=6370997 +shape=vertical
tolerance 10 mm
------------------------------------------------------------
@@ -634,7 +634,7 @@ accept 170.3972098164 87.6222109978
expect 44112.34 -11551573.59
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=vertical +scrolly=-0.25
+ operation +proj=peirce_q +R=6370997 +shape=vertical +scrolly=-0.25
tolerance 10 mm
------------------------------------------------------------
@@ -758,7 +758,7 @@ accept 170.3972098164 87.6222109978
expect 44112.34 -23363877.80
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=nhemisphere
+ operation +proj=peirce_q +R=6370997 +shape=nhemisphere
tolerance 10 mm
------------------------------------------------------------
@@ -882,7 +882,7 @@ accept 170.3972098164 87.6222109978
expect 44112.34 260730.62
------------------------------------------------------------
- operation +proj=peirce_q +R=6370997 +type=shemisphere
+ operation +proj=peirce_q +R=6370997 +shape=shemisphere
tolerance 10 mm
------------------------------------------------------------
@@ -1005,4 +1005,330 @@ expect failure errno coord_transfm_outside_projection_domain
accept 170.3972098164 87.6222109978
expect failure errno coord_transfm_outside_projection_domain
+# Test inverse
+------------------------------------------------------------
+operation +proj=peirce_q +shape=square
+------------------------------------------------------------
+
+#tolerance 1 mm
+# has to bump to this for i386
+tolerance 150 mm
+
+accept 0 90
+expect 0 0
+roundtrip 1
+
+accept 0 0
+expect 8361921.234827487729 -8361921.234827487729
+roundtrip 1
+
+accept 0 -90
+expect 16723842.303160080686 -16723842.303160080686
+#tolerance 2 mm
+roundtrip 1
+#tolerance 1 mm
+
+accept 0 45
+expect 3725360.212758612353 -3725360.212758612353
+roundtrip 1
+
+accept 0 -45
+expect 12998482.090401465073 -12998482.090401465073
+roundtrip 1
+
+accept 45 0
+tolerance 200 mm
+expect 16723842.564696932212 -0.095041956369
+roundtrip 1
+tolerance 150 mm
+
+accept -45 0
+expect 0 -16723842.469654975459
+#roundtrip 1
+
+accept 90 0
+expect 8361921.329869444482 8361921.329869444482
+roundtrip 1
+
+accept -90 0
+expect -8361921.234827487729 -8361921.234827487729
+roundtrip 1
+
+accept 135 0
+expect 0.095041956369 16723842.564696932212
+roundtrip 1
+
+accept -135 0
+expect -16723842.430287310854 -0.039367665210
+#roundtrip 1
+
+accept 179.99 0
+expect -8360808.039828131907 8363034.429826845415
+#roundtrip 1
+
+accept -179.99 0
+expect -8363034.429826845415 8360808.039828131907
+#roundtrip 1
+
+accept 45 45
+expect 5299570.257319082506 0
+roundtrip 1
+
+accept -45 45
+expect 0 -5299570.257319079712
+roundtrip 1
+
+accept 90 45
+expect 3725360.212758610491 3725360.212758610491
+roundtrip 1
+
+accept -90 45
+expect -3725360.212758613285 -3725360.212758613285
+roundtrip 1
+
+accept 135 45
+expect 0 5299570.257319079712
+roundtrip 1
+
+accept -135 45
+expect -5299570.257319079712 0
+#roundtrip 1
+
+accept 179.99 45
+expect -3724717.456456150394 3726002.863303491380
+roundtrip 1
+
+accept -179.99 45
+expect -3726002.863303492777 3724717.456456151791
+roundtrip 1
+
+accept 45 -45
+expect 16723842.303160080686 11424272.045840997249
+roundtrip 1
+
+accept -45 -45
+expect 11424272.045840999112 -16723842.303160080686
+roundtrip 1
+
+accept 90 -45
+expect 12998482.090401468799 12998482.090401468799
+roundtrip 1
+
+accept -90 -45
+expect -12998482.090401465073 -12998482.090401465073
+roundtrip 1
+
+accept 135 -45
+expect -11424272.045840999112 16723842.303160080686
+roundtrip 1
+
+accept -135 -45
+expect -16723842.303160080686 -11424272.045840999112
+roundtrip 1
+
+accept 179.99 -45
+expect -12997839.439856586978 12999124.846703927964
+roundtrip 1
+
+accept -179.99 -45
+expect -12999124.846703927964 12997839.439856585115
+roundtrip 1
+
+accept 45 -89.999
+expect 16723842.303160080686 16723730.983657168224
+#roundtrip 1
+
+accept -45 -89.999
+expect 16723730.983657168224 -16723842.303160080686
+#roundtrip 1
+
+accept 90 -89.999
+expect 16723763.588384689763 16723763.588384689763
+roundtrip 1
+
+accept -90 -89.999
+expect -16723763.588384689763 -16723763.588384689763
+roundtrip 1
+
+accept 135 -89.999
+expect -16723730.983657168224 16723842.303160080686
+#roundtrip 1
+
+accept -135 -89.999
+expect -16723842.303160080686 -16723730.983657168224
+#roundtrip 1
+
+accept 179.99 -89.999
+expect -16723763.588384689763 16723763.588384689763
+#roundtrip 1
+
+accept -179.99 -89.999
+expect -16723763.588384689763 16723763.588384689763
+#roundtrip 1
+
+# Test inverse
+------------------------------------------------------------
+operation +proj=peirce_q +shape=diamond
+------------------------------------------------------------
+
+#tolerance 1 mm
+# has to bump to this for i386
+tolerance 150 mm
+
+accept 0 90
+expect 0 0
+roundtrip 1
+
+accept 0 -90
+#tolerance 10 mm
+expect 0 -23651084.600117880851
+roundtrip 1
+#tolerance 1 mm
+
+accept 0 45
+expect 0 -5268454.937608348206
+roundtrip 1
+
+accept 0 -45
+expect 0 -18382629.662509534508
+roundtrip 1
+
+accept 45 0
+tolerance 200 mm
+expect 11825542.417788611725 -11825542.552198234946
+roundtrip 1
+tolerance 150 mm
+
+accept -45 0
+expect -11825542.417788611725 -11825542.417788611725
+roundtrip 1
+
+accept 90 0
+expect 11825542.552198234946 0.000000000000
+roundtrip 1
+
+accept -90 0
+expect -11825542.417788611725 0.000000000000
+#tolerance 20 mm
+#roundtrip 1
+#tolerance 1 mm
+
+accept 135 0
+expect 11825542.552198234946 11825542.417788611725
+roundtrip 1
+
+accept -135 0
+expect -11825542.417788611725 11825542.362114325166
+roundtrip 1
+
+accept 179.99 0
+expect 1574.295465656175 11825542.417788611725
+#tolerance 200 mm
+#roundtrip 1
+#tolerance 1 mm
+
+accept -179.99 0
+expect -1574.295465656175 11825542.417788611725
+#tolerance 30 mm
+#roundtrip 1
+#tolerance 1 mm
+
+accept 45 45
+expect 3747362.066324858926 -3747362.066324859392
+roundtrip 1
+
+accept -45 45
+expect -3747362.066324857529 -3747362.066324857995
+roundtrip 1
+
+accept 90 45
+expect 5268454.937608345412 0.000000000000
+#roundtrip 1
+
+accept -90 45
+expect -5268454.937608350068 0.000000000000
+#roundtrip 1
+
+accept 135 45
+expect 3747362.066324858926 3747362.066324857995
+roundtrip 1
+
+accept -135 45
+expect -3747362.066324857529 3747362.066324857529
+roundtrip 1
+
+accept 179.99 45
+expect 908.919898338959 5268454.862826444209
+roundtrip 1
+
+accept -179.99 45
+expect -908.919898338959 5268454.862826446071
+roundtrip 1
+
+accept 45 -45
+expect 19903722.533793020993 -3747362.066324859392
+roundtrip 1
+
+accept -45 -45
+expect -3747362.066324857529 -19903722.533793020993
+roundtrip 1
+
+accept 90 -45
+expect 18382629.662509534508 0.000000000000
+roundtrip 1
+
+accept -90 -45
+expect -18382629.662509530783 0.000000000000
+#tolerance 3 mm
+#roundtrip 1
+#tolerance 1 mm
+
+accept 135 -45
+expect 3747362.066324858926 19903722.533793020993
+roundtrip 1
+
+accept -135 -45
+expect -19903722.533793020993 3747362.066324857529
+roundtrip 1
+
+accept 179.99 -45
+expect 908.919898338959 18382629.737291436642
+#roundtrip 1
+
+accept -179.99 -45
+expect -908.919898338959 18382629.737291432917
+roundtrip 1
+
+accept 45 -89.999
+expect 23651005.885342493653 -78.714775386137
+#roundtrip 1
+
+accept -45 -89.999
+expect -78.714775386137 -23651005.885342493653
+#roundtrip 1
+
+accept 90 -89.999
+expect 23650973.280614964664 0.000000000000
+#roundtrip 1
+
+accept -90 -89.999
+expect -23650973.280614964664 0.000000000000
+#roundtrip 1
+
+accept 135 -89.999
+expect 78.714775386137 23651005.885342493653
+#roundtrip 1
+
+accept -135 -89.999
+expect -23651005.885342493653 78.714775386137
+#roundtrip 1
+
+accept 179.99 -89.999
+expect 0.000000000000 23650973.280614964664
+#roundtrip 1
+
+accept -179.99 -89.999
+expect 0.000000000000 23650973.280614964664
+#roundtrip 1
+
</gie-strict>
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 5ffa461b..1c7fc812 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -6075,6 +6075,38 @@ static const struct {
{"False northing", 2},
}},
+ {"Peirce_Quincuncial",
+ {{"False_Easting", 1},
+ {"False_Northing", 2},
+ {"Central_Meridian", 3},
+ {"Scale_Factor", 4},
+ {"Latitude_Of_Origin", 5},
+ {"Option", 0}},
+ "Peirce Quincuncial (Square)",
+ {
+ {"Latitude of natural origin", 5},
+ {"Longitude of natural origin", 3},
+ {"Scale factor at natural origin", 4},
+ {"False easting", 1},
+ {"False northing", 2},
+ }},
+
+ {"Peirce_Quincuncial",
+ {{"False_Easting", 1},
+ {"False_Northing", 2},
+ {"Central_Meridian", 3},
+ {"Scale_Factor", 4},
+ {"Latitude_Of_Origin", 5},
+ {"Option", 1}},
+ "Peirce Quincuncial (Diamond)",
+ {
+ {"Latitude of natural origin", 5},
+ {"Longitude of natural origin", 3},
+ {"Scale factor at natural origin", 4},
+ {"False easting", 1},
+ {"False northing", 2},
+ }},
+
{
"Unknown_Method",
{{"False_Easting", 1},
@@ -9931,6 +9963,49 @@ TEST(io, projparse_ortho_spherical_on_sphere) {
// ---------------------------------------------------------------------------
+TEST(io, projparse_peirce_q) {
+ std::string input("+proj=peirce_q +shape=square +type=crs");
+ auto obj = PROJStringParser().createFromPROJString(input);
+ auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(
+ crs->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
+ .get()),
+ "+proj=peirce_q +shape=square +lat_0=90 +lon_0=0 +k_0=1 +x_0=0 +y_0=0 "
+ "+datum=WGS84 +units=m +no_defs +type=crs");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(io, projparse_peirce_q_invalid_lat_0) {
+ std::string input("+proj=peirce_q +lat_0=0 +shape=square +type=crs");
+ auto obj = PROJStringParser().createFromPROJString(input);
+ auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_THROW(
+ crs->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
+ .get()),
+ FormattingException);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(io, projparse_peirce_q_invalid_k_0) {
+ std::string input("+proj=peirce_q +k_0=0.5 +shape=square +type=crs");
+ auto obj = PROJStringParser().createFromPROJString(input);
+ auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_THROW(
+ crs->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
+ .get()),
+ FormattingException);
+}
+
+// ---------------------------------------------------------------------------
+
TEST(io, projparse_axisswap_unitconvert_longlat_proj) {
std::string input =
"+type=crs +proj=pipeline +step +proj=axisswap +order=2,1 +step "