Skip to content

Commit

Permalink
Merge pull request #4228 from jjimenezshaw/local-geographic
Browse files Browse the repository at this point in the history
Add new Conversion "Local Orthographic"
  • Loading branch information
rouault authored Aug 16, 2024
2 parents 8cf1baf + 221b2d5 commit c83e18e
Show file tree
Hide file tree
Showing 16 changed files with 287 additions and 33 deletions.
21 changes: 20 additions & 1 deletion docs/source/operations/projections/ortho.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ around a given latitude and longitude.
ellipsoid must be forced to a sphere, for example by adding a ``+f=0``
parameter.

This projection method corresponds to ``EPSG:9840``.
.. note:: Parameters ``k_0`` and ``alpha`` are added in PROJ 9.5.0

This projection method corresponds to ``EPSG:9840``
(or ``EPSG:1130`` with ``k_0`` or ``alpha``).

Parameters
################################################################################
Expand All @@ -48,6 +51,22 @@ Parameters

.. include:: ../options/lat_0.rst

.. option:: +alpha=<value>

.. versionadded:: 9.5.0

Azimuth clockwise from north at the center of projection.

*Defaults to 0.0.*

.. option:: +k_0=<value>

.. versionadded:: 9.5.0

Scale factor. Determines scale factor used in the projection.

*Defaults to 1.0.*

.. include:: ../options/ellps.rst

.. include:: ../options/R.rst
Expand Down
7 changes: 7 additions & 0 deletions include/proj/coordinateoperation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,13 @@ class PROJ_GCC_DLL Conversion : public SingleOperation {
const common::Angle &centerLong, const common::Length &falseEasting,
const common::Length &falseNorthing);

PROJ_DLL static ConversionNNPtr createLocalOrthographic(
const util::PropertyMap &properties, const common::Angle &centerLat,
const common::Angle &centerLong,
const common::Angle &azimuthInitialLine, const common::Scale &scale,
const common::Length &falseEasting,
const common::Length &falseNorthing);

PROJ_DLL static ConversionNNPtr createAmericanPolyconic(
const util::PropertyMap &properties, const common::Angle &centerLat,
const common::Angle &centerLong, const common::Length &falseEasting,
Expand Down
8 changes: 4 additions & 4 deletions scripts/build_esri_projection_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@
- Standard_Parallel_2: EPSG_NAME_PARAMETER_LATITUDE_2ND_STD_PARALLEL
- Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_FALSE_ORIGIN
# From GDAL autotest
# From GDAL autotest
- WKT2_name: EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP
Params:
- False_Easting: EPSG_NAME_PARAMETER_EASTING_FALSE_ORIGIN
Expand Down Expand Up @@ -456,12 +456,12 @@
- Latitude_Of_Center: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
- Local:
WKT2_name: EPSG_NAME_METHOD_ORTHOGRAPHIC
WKT2_name: EPSG_NAME_METHOD_LOCAL_ORTHOGRAPHIC
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Scale_Factor: 1.0
- Azimuth: 0.0
- Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_PROJECTION_CENTRE
- Azimuth: EPSG_NAME_PARAMETER_AZIMUTH_PROJECTION_CENTRE
- Longitude_Of_Center: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Latitude_Of_Center: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
Expand Down
2 changes: 2 additions & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ osgeo::proj::operation::Conversion::createLambertConicConformal_2SP_Michigan(osg
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&)
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&)
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&)
osgeo::proj::operation::Conversion::createLocalOrthographic(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle 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&)
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&)
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&)
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&)
Expand Down Expand Up @@ -938,6 +939,7 @@ proj_create_conversion_lambert_conic_conformal_2sp_belgium
proj_create_conversion_lambert_conic_conformal_2sp_michigan
proj_create_conversion_lambert_cylindrical_equal_area
proj_create_conversion_lambert_cylindrical_equal_area_spherical
proj_create_conversion_local_orthographic
proj_create_conversion_mercator_variant_a
proj_create_conversion_mercator_variant_b
proj_create_conversion_miller_cylindrical
Expand Down
33 changes: 33 additions & 0 deletions src/iso19111/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6775,6 +6775,39 @@ PJ *proj_create_conversion_orthographic(
}
// ---------------------------------------------------------------------------

/** \brief Instantiate a ProjectedCRS with a conversion based on the Local
* Orthographic projection method.
*
* See osgeo::proj::operation::Conversion::createLocalOrthographic().
*
* Linear parameters are expressed in (linear_unit_name,
* linear_unit_conv_factor).
* Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor).
*/
PJ *proj_create_conversion_local_orthographic(
PJ_CONTEXT *ctx, double center_lat, double center_long, double azimuth,
double scale, double false_easting, double false_northing,
const char *ang_unit_name, double ang_unit_conv_factor,
const char *linear_unit_name, double linear_unit_conv_factor) {
SANITIZE_CTX(ctx);
try {
UnitOfMeasure linearUnit(
createLinearUnit(linear_unit_name, linear_unit_conv_factor));
UnitOfMeasure angUnit(
createAngularUnit(ang_unit_name, ang_unit_conv_factor));
auto conv = Conversion::createLocalOrthographic(
PropertyMap(), Angle(center_lat, angUnit),
Angle(center_long, angUnit), Angle(azimuth, angUnit), Scale(scale),
Length(false_easting, linearUnit),
Length(false_northing, linearUnit));
return proj_create_conversion(ctx, conv);
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
return nullptr;
}
// ---------------------------------------------------------------------------

/** \brief Instantiate a ProjectedCRS with a conversion based on the American
* Polyconic projection method.
*
Expand Down
7 changes: 7 additions & 0 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11866,6 +11866,13 @@ PROJStringParser::Private::buildProjectedCRS(int iStep,
axisType = AxisType::SOUTH_POLE;
}
}
} else if (step.name == "ortho") {
const std::string &k = getParamValueK(step);
if ((!k.empty() && getNumericValue(k) != 1.0) ||
(hasParamValue(step, "alpha") &&
getNumericValue(getParamValue(step, "alpha")) != 0.0)) {
mapping = getMapping(EPSG_CODE_METHOD_LOCAL_ORTHOGRAPHIC);
}
}

UnitOfMeasure unit = buildUnit(step, "units", "to_meter");
Expand Down
30 changes: 30 additions & 0 deletions src/iso19111/operation/conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,36 @@ ConversionNNPtr Conversion::createOrthographic(

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

/** \brief Instantiate a conversion based on the
* <a href="../../../operations/projections/ortho.html">
* Orthographic</a> projection method.
*
* This method is defined as
* <a href="https://epsg.org/coord-operation-method_1130/index.html">
* EPSG:1130</a>.
*
* @param properties See \ref general_properties of the conversion. If the name
* is not provided, it is automatically set.
* @param centerLat See \ref center_latitude
* @param centerLong See \ref center_longitude
* @param azimuthInitialLine See \ref azimuth_initial_line
* @param scale See \ref scale_factor_initial_line
* @param falseEasting See \ref false_easting
* @param falseNorthing See \ref false_northing
* @return a new Conversion.
*/
ConversionNNPtr Conversion::createLocalOrthographic(
const util::PropertyMap &properties, const common::Angle &centerLat,
const common::Angle &centerLong, const common::Angle &azimuthInitialLine,
const common::Scale &scale, const common::Length &falseEasting,
const common::Length &falseNorthing) {
return create(properties, EPSG_CODE_METHOD_LOCAL_ORTHOGRAPHIC,
createParams(centerLat, centerLong, azimuthInitialLine, scale,
falseEasting, falseNorthing));
}

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

/** \brief Instantiate a conversion based on the
* <a href="../../../operations/projections/poly.html">
* American Polyconic</a> projection method.
Expand Down
10 changes: 6 additions & 4 deletions src/iso19111/operation/esriparammappings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,10 @@ static const ESRIParamMapping paramsESRI_Local[] = {
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
{"False_Northing", EPSG_NAME_PARAMETER_FALSE_NORTHING,
EPSG_CODE_PARAMETER_FALSE_NORTHING, "0.0", false},
{"Scale_Factor", nullptr, 0, "1.0", false},
{"Azimuth", nullptr, 0, "0.0", false},
{"Scale_Factor", EPSG_NAME_PARAMETER_SCALE_FACTOR_PROJECTION_CENTRE,
EPSG_CODE_PARAMETER_SCALE_FACTOR_PROJECTION_CENTRE, "1.0", false},
{"Azimuth", EPSG_NAME_PARAMETER_AZIMUTH_PROJECTION_CENTRE,
EPSG_CODE_PARAMETER_AZIMUTH_PROJECTION_CENTRE, "0.0", false},
{"Longitude_Of_Center", EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{"Latitude_Of_Center", EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
Expand Down Expand Up @@ -1089,8 +1091,8 @@ static const ESRIMethodMapping esriMappings[] = {
paramsESRI_New_Zealand_Map_Grid},
{"Orthographic", PROJ_WKT2_NAME_ORTHOGRAPHIC_SPHERICAL, 0,
paramsESRI_Orthographic},
{"Local", EPSG_NAME_METHOD_ORTHOGRAPHIC, EPSG_CODE_METHOD_ORTHOGRAPHIC,
paramsESRI_Local},
{"Local", EPSG_NAME_METHOD_LOCAL_ORTHOGRAPHIC,
EPSG_CODE_METHOD_LOCAL_ORTHOGRAPHIC, paramsESRI_Local},
{"Winkel_Tripel", "Winkel Tripel", 0, paramsESRI_Winkel_Tripel},
{"Aitoff", "Aitoff", 0, paramsESRI_Aitoff},
{"Flat_Polar_Quartic", PROJ_WKT2_NAME_METHOD_FLAT_POLAR_QUARTIC, 0,
Expand Down
12 changes: 12 additions & 0 deletions src/iso19111/operation/parammappings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ static const ParamMapping *const paramsHomTwoPoint[] = {
&paramFalseNorthingProjectionCentre,
nullptr};

static const ParamMapping *const paramsNatOriginAzimuthScale[] = {
&paramLatitudeNatOrigin,
&paramLongitudeNatOrigin,
&paramAzimuth,
&paramScaleFactorProjectionCentre,
&paramFalseEasting,
&paramFalseNorthing,
nullptr};

static const ParamMapping *const paramsIMWP[] = {
&paramLongitudeNatOrigin, &paramLatFirstPoint, &paramLatSecondPoint,
&paramFalseEasting, &paramFalseNorthing, nullptr};
Expand Down Expand Up @@ -822,6 +831,9 @@ static const MethodMapping projectionMethodMappings[] = {
{EPSG_NAME_METHOD_ORTHOGRAPHIC, EPSG_CODE_METHOD_ORTHOGRAPHIC,
"Orthographic", "ortho", nullptr, paramsNatOrigin},

{EPSG_NAME_METHOD_LOCAL_ORTHOGRAPHIC, EPSG_CODE_METHOD_LOCAL_ORTHOGRAPHIC,
"Local Orthographic", "ortho", nullptr, paramsNatOriginAzimuthScale},

{PROJ_WKT2_NAME_ORTHOGRAPHIC_SPHERICAL, 0, "Orthographic", "ortho", "f=0",
paramsNatOrigin},

Expand Down
6 changes: 6 additions & 0 deletions src/proj.h
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,12 @@ PJ PROJ_DLL *proj_create_conversion_orthographic(
double ang_unit_conv_factor, const char *linear_unit_name,
double linear_unit_conv_factor);

PJ PROJ_DLL *proj_create_conversion_local_orthographic(
PJ_CONTEXT *ctx, double center_lat, double center_long, double azimuth,
double scale, double false_easting, double false_northing,
const char *ang_unit_name, double ang_unit_conv_factor,
const char *linear_unit_name, double linear_unit_conv_factor);

PJ PROJ_DLL *proj_create_conversion_american_polyconic(
PJ_CONTEXT *ctx, double center_lat, double center_long,
double false_easting, double false_northing, const char *ang_unit_name,
Expand Down
3 changes: 3 additions & 0 deletions src/proj_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@
#define EPSG_NAME_METHOD_ORTHOGRAPHIC "Orthographic"
#define EPSG_CODE_METHOD_ORTHOGRAPHIC 9840

#define EPSG_NAME_METHOD_LOCAL_ORTHOGRAPHIC "Local Orthographic"
#define EPSG_CODE_METHOD_LOCAL_ORTHOGRAPHIC 1130

#define PROJ_WKT2_NAME_ORTHOGRAPHIC_SPHERICAL "Orthographic (Spherical)"

#define PROJ_WKT2_NAME_METHOD_PATTERSON "Patterson"
Expand Down
29 changes: 26 additions & 3 deletions src/projections/ortho.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct pj_ortho_data {
double y_shift;
double y_scale;
enum pj_ortho_ns::Mode mode;
double sinalpha;
double cosalpha;
};
} // anonymous namespace

Expand Down Expand Up @@ -72,6 +74,11 @@ static PJ_XY ortho_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
break;
}
xy.x = cosphi * sin(lp.lam);

const double xp = xy.x;
const double yp = xy.y;
xy.x = (xp * Q->cosalpha - yp * Q->sinalpha) * P->k0;
xy.y = (xp * Q->sinalpha + yp * Q->cosalpha) * P->k0;
return xy;
}

Expand All @@ -83,6 +90,11 @@ static PJ_LP ortho_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
lp.lam = HUGE_VAL;
lp.phi = HUGE_VAL;

const double xf = xy.x;
const double yf = xy.y;
xy.x = (Q->cosalpha * xf + Q->sinalpha * yf) / P->k0;
xy.y = (-Q->sinalpha * xf + Q->cosalpha * yf) / P->k0;

const double rh = hypot(xy.x, xy.y);
sinc = rh;
if (sinc > 1.) {
Expand Down Expand Up @@ -150,9 +162,11 @@ static PJ_XY ortho_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
}

const double nu = 1.0 / sqrt(1.0 - P->es * sinphi * sinphi);
xy.x = nu * cosphi * sinlam;
xy.y = nu * (sinphi * Q->cosph0 - cosphi * Q->sinph0 * coslam) +
P->es * (Q->nu0 * Q->sinph0 - nu * sinphi) * Q->cosph0;
const double xp = nu * cosphi * sinlam;
const double yp = nu * (sinphi * Q->cosph0 - cosphi * Q->sinph0 * coslam) +
P->es * (Q->nu0 * Q->sinph0 - nu * sinphi) * Q->cosph0;
xy.x = (Q->cosalpha * xp - Q->sinalpha * yp) * P->k0;
xy.y = (Q->sinalpha * xp + Q->cosalpha * yp) * P->k0;

return xy;
}
Expand All @@ -163,6 +177,11 @@ static PJ_LP ortho_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */

const auto SQ = [](double x) { return x * x; };

const double xf = xy.x;
const double yf = xy.y;
xy.x = (Q->cosalpha * xf + Q->sinalpha * yf) / P->k0;
xy.y = (-Q->sinalpha * xf + Q->cosalpha * yf) / P->k0;

if (Q->mode == pj_ortho_ns::N_POLE || Q->mode == pj_ortho_ns::S_POLE) {
// Polar case. Forward case equations can be simplified as:
// xy.x = nu * cosphi * sinlam
Expand Down Expand Up @@ -309,6 +328,10 @@ PJ *PJ_PROJECTION(ortho) {
P->fwd = ortho_e_forward;
}

const double alpha = pj_param(P->ctx, P->params, "ralpha").f;
Q->sinalpha = sin(alpha);
Q->cosalpha = cos(alpha);

return P;
}

Expand Down
14 changes: 14 additions & 0 deletions test/gie/builtins.gie
Original file line number Diff line number Diff line change
Expand Up @@ -5415,6 +5415,20 @@ direction inverse
accept 0 6378137.1
expect failure errno coord_transfm_outside_projection_domain

-------------------------------------------------------------------------------
# Test the Local Orthographic formulation

# Test data from Guidance Note 7 part 2, August 2024, p. 101
# Note: The parameters of the CRS in the example are not
# exactly the parameters of the CRS in the database for EPSG:10622
-------------------------------------------------------------------------------
operation +proj=ortho +lat_0=37.628969166666664 +lon_0=-122.39394166666668 +k_0=0.9999968 +alpha=27.7927777777777 +x_0=0 +y_0=0 +ellps=GRS80
-------------------------------------------------------------------------------
tolerance 0.1 mm
accept -122.3846388888889 37.62607694444444
expect 876.13676 98.97406
roundtrip 100


===============================================================================
# Perspective Conic
Expand Down
Loading

0 comments on commit c83e18e

Please sign in to comment.