Skip to content

Commit bee4a90

Browse files
committed
Implement 'Vertical Offset by velocity grid (NRCan byn)' method
1 parent b5d33ab commit bee4a90

File tree

6 files changed

+211
-3
lines changed

6 files changed

+211
-3
lines changed

data/sql/customizations.sql

+8-1
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,19 @@ INSERT INTO usage SELECT
188188
scope_code
189189
FROM usage WHERE object_table_name = 'grid_transformation' AND object_auth_name = 'EPSG' AND object_code = '9123';
190190

191-
-- Duplicate EPSG:10015 with NAD83(CSRS)v7 as interpolation CRS
191+
-- Duplicate EPSG:10115, 10116, 10117 with NAD83(CSRS)v7 as interpolation CRS
192192
INSERT INTO "grid_transformation" VALUES
193193
('PROJ','EPSG_10115_WITH_NAD83CSRSV7_INTERPOLATION','CGVD28 height to CGVD2013a(2010) height (1)','Equivalent to HT2_2010v70 hybrid geoid model minus CGG2013a geoid model (i.e. CT code 9986 minus CT 9247 = CT 9987 minus CT 10109). Specifies NAD83(CSRS)v7 (code 8255) as interpolation CRS.','EPSG','1112','Vertical Offset by Grid Interpolation (NRCan byn)','EPSG','5713','EPSG','9245',0.05,'EPSG','8732','Vertical offset file','HT2_2010v70_CGG2013a.byn',NULL,NULL,NULL,NULL,'EPSG','8255','NR-Can HT2 2010',0);
194194

195195
INSERT INTO "usage" VALUES('PROJ','USAGE_EPSG_10115_WITH_NAD83CSRSV7_INTERPOLATION','grid_transformation','PROJ','EPSG_10115_WITH_NAD83CSRSV7_INTERPOLATION','EPSG','1061','EPSG','1133');
196196

197+
INSERT INTO "grid_transformation" VALUES('PROJ','EPSG_10116_WITH_NAD83CSRSV7_INTERPOLATION','CGVD2013a(2010) height to CGVD2013a(2002) height (1)',' Specifies NAD83(CSRS)v7 (code 8255) as interpolation CRS. Equivalent to CGVD28 to CGVD2013a(2002) minus CGVD28 to CGVD2013a(2010) (i.e. CT code 10114 minus CT 10115).','EPSG','1113','Vertical Offset by velocity grid (NRCan byn)','EPSG','9245','EPSG','20034',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8255','EPSG-Can',0);
198+
INSERT INTO "usage" VALUES('PROJ','USAGE_EPSG_10116_WITH_NAD83CSRSV7_INTERPOLATION','grid_transformation','PROJ','EPSG_10116_WITH_NAD83CSRSV7_INTERPOLATION','EPSG','1061','EPSG','1026');
199+
200+
INSERT INTO "grid_transformation" VALUES('PROJ','EPSG_10117_WITH_NAD83CSRSV7_INTERPOLATION','CGVD2013a(2010) height to CGVD2013a(1997) height (1)','Specifies NAD83(CSRS)v7 (code 8255) as interpolation CRS. Equivalent to CGVD28 to CGVD2013a(1997) minus CGVD28 to CGVD2013a(2010) (i.e. CT code 10113 minus CT 10115).','EPSG','1113','Vertical Offset by velocity grid (NRCan byn)','EPSG','9245','EPSG','20035',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8255','EPSG-Can',0);
201+
INSERT INTO "usage" VALUES('PROJ','USAGE_EPSG_10117_WITH_NAD83CSRSV7_INTERPOLATION','grid_transformation','PROJ','EPSG_10117_WITH_NAD83CSRSV7_INTERPOLATION','EPSG','1061','EPSG','1026');
202+
203+
197204
-- Define the allowed authorities, and their precedence, when researching a
198205
-- coordinate operation
199206

data/sql/grid_transformation.sql

+6
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,12 @@ INSERT INTO "grid_transformation" VALUES('EPSG','10114','CGVD28 height to CGVD20
14401440
INSERT INTO "usage" VALUES('EPSG','18322','grid_transformation','EPSG','10114','EPSG','1061','EPSG','1133');
14411441
INSERT INTO "grid_transformation" VALUES('EPSG','10115','CGVD28 height to CGVD2013a(2010) height (1)','Equivalent to HT2_2010v70 hybrid geoid model minus CGG2013a geoid model (i.e. CT code 9986 minus CT 9247 = CT 9987 minus CT 10109). Specifies NAD83(CSRS)v6 as interpolation CRS, but NAD83(CSRS)v7 (code 8255) may equally be used.','EPSG','1112','Vertical Offset by Grid Interpolation (NRCan byn)','EPSG','5713','EPSG','9245',0.05,'EPSG','8732','Vertical offset file','HT2_2010v70_CGG2013a.byn',NULL,NULL,NULL,NULL,'EPSG','8252','NR-Can HT2 2010',0);
14421442
INSERT INTO "usage" VALUES('EPSG','18323','grid_transformation','EPSG','10115','EPSG','1061','EPSG','1133');
1443+
INSERT INTO "grid_transformation" VALUES('EPSG','10116','CGVD2013a(2010) height to CGVD2013a(2002) height (1)','Interpolation CRS = NAD83(CSRS) 2010, i.e. may be any one of NAD83(CSRS)v6, v7 or v8 (CRS codes 8252, 8255 or 10414). Equivalent to CGVD28 to CGVD2013a(2002) minus CGVD28 to CGVD2013a(2010) (i.e. CT code 10114 minus CT 10115).','EPSG','1113','Vertical Offset by velocity grid (NRCan byn)','EPSG','9245','EPSG','20034',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8252','EPSG-Can',0);
1444+
INSERT INTO "usage" VALUES('EPSG','18325','grid_transformation','EPSG','10116','EPSG','1061','EPSG','1026');
1445+
INSERT INTO "grid_transformation" VALUES('EPSG','10117','CGVD2013a(2010) height to CGVD2013a(1997) height (1)','Interpolation CRS = NAD83(CSRS) 2010, i.e. may be any one of NAD83(CSRS)v6, v7 or v8 (CRS codes 8252, 8255 or 10414). Equivalent to CGVD28 to CGVD2013a(1997) minus CGVD28 to CGVD2013a(2010) (i.e. CT code 10113 minus CT 10115).','EPSG','1113','Vertical Offset by velocity grid (NRCan byn)','EPSG','9245','EPSG','20035',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8252','EPSG-Can',0);
1446+
INSERT INTO "usage" VALUES('EPSG','18352','grid_transformation','EPSG','10117','EPSG','1061','EPSG','1026');
1447+
INSERT INTO "grid_transformation" VALUES('EPSG','10118','CGVD2013a(2002) height to CGVD2013a(1997) height (1)','Equivalent to CGVD28 to CGVD2013a(1997) minus CGVD28 to CGVD2013a(2002) (i.e. CT code 10113 minus CT 10114).','EPSG','1113','Vertical Offset by velocity grid (NRCan byn)','EPSG','20034','EPSG','20035',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8246','EPSG-Can',0);
1448+
INSERT INTO "usage" VALUES('EPSG','18328','grid_transformation','EPSG','10118','EPSG','1061','EPSG','1026');
14431449
INSERT INTO "grid_transformation" VALUES('EPSG','10119','NAD83(CSRS)v4 to NAD83(CSRS)v2 (1)','','EPSG','1114','Geographic3D Offset by velocity grid (NRCan byn)','EPSG','8244','EPSG','8235',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8246','EPSG-Can cvg70',0);
14441450
INSERT INTO "usage" VALUES('EPSG','18201','grid_transformation','EPSG','10119','EPSG','1061','EPSG','1026');
14451451
INSERT INTO "grid_transformation" VALUES('EPSG','10120','NAD83(CSRS)v4 to NAD83(CSRS)v3 (1)','','EPSG','1114','Geographic3D Offset by velocity grid (NRCan byn)','EPSG','8244','EPSG','8239',0.05,'EPSG','1050','Point motion velocity grid file','NAD83v70VG.gvb',NULL,NULL,NULL,NULL,'EPSG','8246','EPSG-Can cvg70',0);

scripts/build_db.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ def fill_helmert_transformation(proj_db_cursor):
692692
'?,?,?, ?, ?,?,?, ?,?, ?,?, ?, ?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?, ?,?,?,?,?, ?,?)', arg)
693693

694694
def fill_grid_transformation(proj_db_cursor):
695-
proj_db_cursor.execute("SELECT coord_op_code, coord_op_name, coord_op_method_code, coord_op_method_name, source_crs_code, target_crs_code, coord_op_accuracy, coord_tfm_version, epsg_coordoperation.deprecated, epsg_coordoperation.remarks FROM epsg.epsg_coordoperation LEFT JOIN epsg.epsg_coordoperationmethod USING (coord_op_method_code) WHERE coord_op_type IN ('transformation', 'point motion operation') AND (coord_op_method_name LIKE 'Geographic3D to%' OR coord_op_method_name LIKE 'Geog3D to%' OR coord_op_method_name LIKE 'Point motion by grid%' OR coord_op_method_name LIKE 'Vertical Offset by Grid Interpolation%' OR coord_op_method_name IN ('NADCON', 'NADCON5 (2D)', 'NADCON5 (3D)', 'NTv1', 'NTv2', 'VERTCON', 'Geocentric translation by Grid Interpolation (IGN)', 'Geographic3D Offset by velocity grid (NRCan byn)'))")
695+
proj_db_cursor.execute("SELECT coord_op_code, coord_op_name, coord_op_method_code, coord_op_method_name, source_crs_code, target_crs_code, coord_op_accuracy, coord_tfm_version, epsg_coordoperation.deprecated, epsg_coordoperation.remarks FROM epsg.epsg_coordoperation LEFT JOIN epsg.epsg_coordoperationmethod USING (coord_op_method_code) WHERE coord_op_type IN ('transformation', 'point motion operation') AND (coord_op_method_name LIKE 'Geographic3D to%' OR coord_op_method_name LIKE 'Geog3D to%' OR coord_op_method_name LIKE 'Point motion by grid%' OR coord_op_method_name LIKE 'Vertical Offset by Grid Interpolation%' OR coord_op_method_name IN ('NADCON', 'NADCON5 (2D)', 'NADCON5 (3D)', 'NTv1', 'NTv2', 'VERTCON', 'Geocentric translation by Grid Interpolation (IGN)', 'Geographic3D Offset by velocity grid (NRCan byn)', 'Vertical Offset by velocity grid (NRCan byn)'))")
696696
for (code, name, method_code, method_name, source_crs_code, target_crs_code, coord_op_accuracy, coord_tfm_version, deprecated, remarks) in proj_db_cursor.fetchall():
697697
expected_order = 1
698698
max_n_params = 3 if method_name == 'Geocentric translation by Grid Interpolation (IGN)' else 2
@@ -775,13 +775,14 @@ def fill_grid_transformation(proj_db_cursor):
775775
# 1105: Geog3D to Geog2D+GravityRelatedHeight (ITAL2005)
776776
# 1110: Geog3D to Geog2D+Depth (Gravsoft)
777777
# 1112: Vertical Offset by Grid Interpolation (NRCan byn)
778+
# 1113: Vertical Offset by velocity grid (NRCan byn)
778779
# 1114: Geographic3D Offset by velocity grid (NRCan byn)
779780
# 1115: Geog3D to Geog2D+Depth (txt)
780781
# 1118: Geog3D to Geog2D+GravityRelatedHeight (ISG)
781782
# 1122: Geog3D to Geog2D+Depth (gtx)
782783
# WARNING: update Transformation::isGeographic3DToGravityRelatedHeight()
783784
# in src/iso19111/operation/singleoperation.cpp if adding new methods
784-
elif method_code in (1071, 1080, 1081, 1083, 1084, 1085, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1100, 1101, 1103, 1105, 1110, 1112, 1114, 1115, 1118, 1122) and n_params == 2:
785+
elif method_code in (1071, 1080, 1081, 1083, 1084, 1085, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1100, 1101, 1103, 1105, 1110, 1112, 1113, 1114, 1115, 1118, 1122) and n_params == 2:
785786
assert param_code[1] == 1048, (code, method_code, param_code[1])
786787
interpolation_crs_auth_name = EPSG_AUTHORITY
787788
interpolation_crs_code = str(int(param_value[1])) # needed to avoid codes like XXXX.0

src/iso19111/operation/singleoperation.cpp

+148
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,34 @@ _getGeographic3DOffsetByVelocityGridFilename(const SingleOperation *op,
19911991

19921992
// ---------------------------------------------------------------------------
19931993

1994+
//! @cond Doxygen_Suppress
1995+
static const std::string &
1996+
_getVerticalOffsetByVelocityGridFilename(const SingleOperation *op,
1997+
bool allowInverse) {
1998+
1999+
const auto &l_method = op->method();
2000+
const auto &methodName = l_method->nameStr();
2001+
if (l_method->getEPSGCode() ==
2002+
EPSG_CODE_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN ||
2003+
(allowInverse &&
2004+
ci_equal(
2005+
methodName,
2006+
INVERSE_OF +
2007+
EPSG_NAME_METHOD_GEOGRAPHIC3D_OFFSET_BY_VELOCITY_GRID_NRCAN))) {
2008+
const auto &fileParameter = op->parameterValue(
2009+
EPSG_NAME_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE,
2010+
EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE);
2011+
if (fileParameter &&
2012+
fileParameter->type() == ParameterValue::Type::FILENAME) {
2013+
return fileParameter->valueFile();
2014+
}
2015+
}
2016+
return nullString;
2017+
}
2018+
//! @endcond
2019+
2020+
// ---------------------------------------------------------------------------
2021+
19942022
//! @cond Doxygen_Suppress
19952023
static const std::string &
19962024
_getHeightToGeographic3DFilename(const SingleOperation *op, bool allowInverse) {
@@ -2485,6 +2513,45 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames(
24852513
}
24862514
}
24872515

2516+
const auto &verticalOffsetByVelocityGridFilename =
2517+
_getVerticalOffsetByVelocityGridFilename(this, false);
2518+
if (!verticalOffsetByVelocityGridFilename.empty()) {
2519+
if (databaseContext->lookForGridAlternative(
2520+
verticalOffsetByVelocityGridFilename, projFilename,
2521+
projGridFormat, inverseDirection)) {
2522+
2523+
if (inverseDirection) {
2524+
throw util::UnsupportedOperationException(
2525+
"Inverse direction for "
2526+
"VerticalOffsetByVelocityGrid not supported");
2527+
}
2528+
2529+
if (verticalOffsetByVelocityGridFilename == projFilename) {
2530+
return self;
2531+
}
2532+
2533+
const auto l_sourceCRSNull = sourceCRS();
2534+
const auto l_targetCRSNull = targetCRS();
2535+
if (l_sourceCRSNull == nullptr) {
2536+
throw util::UnsupportedOperationException("Missing sourceCRS");
2537+
}
2538+
if (l_targetCRSNull == nullptr) {
2539+
throw util::UnsupportedOperationException("Missing targetCRS");
2540+
}
2541+
auto l_sourceCRS = NN_NO_CHECK(l_sourceCRSNull);
2542+
auto l_targetCRS = NN_NO_CHECK(l_targetCRSNull);
2543+
auto parameters =
2544+
std::vector<OperationParameterNNPtr>{createOpParamNameEPSGCode(
2545+
EPSG_CODE_PARAMETER_POINT_MOTION_VELOCITY_GRID_FILE)};
2546+
return Transformation::create(
2547+
createSimilarPropertiesOperation(self), l_sourceCRS,
2548+
l_targetCRS, l_interpolationCRS,
2549+
createSimilarPropertiesMethod(method()), parameters,
2550+
{ParameterValue::createFilename(projFilename)},
2551+
coordinateOperationAccuracies());
2552+
}
2553+
}
2554+
24882555
bool reverseOffsetSign = false;
24892556
if (methodEPSGCode == EPSG_CODE_METHOD_VERTCON ||
24902557
isRegularVerticalGridMethod(methodEPSGCode, reverseOffsetSign)) {
@@ -4029,6 +4096,87 @@ bool SingleOperation::exportToPROJStringGeneric(
40294096
return true;
40304097
}
40314098

4099+
const auto &verticalOffsetByVelocityGridFilename =
4100+
_getVerticalOffsetByVelocityGridFilename(this, true);
4101+
if (!verticalOffsetByVelocityGridFilename.empty()) {
4102+
4103+
const auto &interpCRS = interpolationCRS();
4104+
if (!interpCRS) {
4105+
throw io::FormattingException(
4106+
"InterpolationCRS required "
4107+
"for"
4108+
" " EPSG_NAME_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN);
4109+
}
4110+
4111+
auto interpCRSGeog =
4112+
dynamic_cast<const crs::GeographicCRS *>(interpCRS.get());
4113+
if (!interpCRSGeog) {
4114+
throw io::FormattingException(
4115+
concat("Can apply ", methodName,
4116+
" only to a GeographicCRS interpolation CRS"));
4117+
}
4118+
4119+
if (isMethodInverseOf) {
4120+
formatter->startInversion();
4121+
}
4122+
formatter->addStep("push");
4123+
formatter->addParam("v_1");
4124+
formatter->addParam("v_2");
4125+
4126+
formatter->addStep("cart");
4127+
interpCRSGeog->ellipsoid()->_exportToPROJString(formatter);
4128+
4129+
formatter->addStep("deformation");
4130+
auto srcName = sourceCRS()->nameStr();
4131+
auto dstName = targetCRS()->nameStr();
4132+
const struct {
4133+
const char *name;
4134+
double epoch;
4135+
} realizationEpochs[] = {
4136+
{"CGVD2013a(1997) height", 1997.0},
4137+
{"CGVD2013a(2002) height", 2002.0},
4138+
{"CGVD2013a(2010) height", 2010.0},
4139+
};
4140+
double sourceYear = 0.0;
4141+
double targetYear = 0.0;
4142+
for (const auto &iter : realizationEpochs) {
4143+
if (iter.name == srcName)
4144+
sourceYear = iter.epoch;
4145+
if (iter.name == dstName)
4146+
targetYear = iter.epoch;
4147+
}
4148+
if (sourceYear == 0.0) {
4149+
throw io::FormattingException(
4150+
"For"
4151+
" " EPSG_NAME_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN
4152+
", missing epoch for source CRS");
4153+
}
4154+
if (targetYear == 0.0) {
4155+
throw io::FormattingException(
4156+
"For"
4157+
" " EPSG_NAME_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN
4158+
", missing epoch for target CRS");
4159+
}
4160+
formatter->addParam("dt", targetYear - sourceYear);
4161+
formatter->addParam("grids", verticalOffsetByVelocityGridFilename);
4162+
interpCRSGeog->ellipsoid()->_exportToPROJString(formatter);
4163+
4164+
formatter->startInversion();
4165+
formatter->addStep("cart");
4166+
interpCRSGeog->ellipsoid()->_exportToPROJString(formatter);
4167+
formatter->stopInversion();
4168+
4169+
formatter->addStep("pop");
4170+
formatter->addParam("v_1");
4171+
formatter->addParam("v_2");
4172+
4173+
if (isMethodInverseOf) {
4174+
formatter->stopInversion();
4175+
}
4176+
4177+
return true;
4178+
}
4179+
40324180
const auto &heightFilename = _getHeightToGeographic3DFilename(this, true);
40334181
if (!heightFilename.empty()) {
40344182
auto l_targetCRS = targetCRS();

src/proj_constants.h

+6
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,12 @@
596596

597597
/* ------------------------------------------------------------------------ */
598598

599+
#define EPSG_NAME_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN \
600+
"Vertical Offset by velocity grid (NRCan byn)"
601+
#define EPSG_CODE_METHOD_VERTICAL_OFFSET_BY_VELOCITY_GRID_NRCAN 1113
602+
603+
/* ------------------------------------------------------------------------ */
604+
599605
#define PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D \
600606
"GravityRelatedHeight to Geographic3D"
601607

test/unit/test_operationfactory.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -10003,3 +10003,43 @@ TEST(operation, createOperation_test_createOperationsWithDatumPivot_iter_1) {
1000310003
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
1000410004
"+proj=noop");
1000510005
}
10006+
10007+
// ---------------------------------------------------------------------------
10008+
10009+
TEST(operation, createOperation_Vrtical_Offset_by_velocity_grid) {
10010+
auto dbContext = DatabaseContext::create();
10011+
10012+
auto objSrc = createFromUserInput("NAD83(CSRS)v7 + CGVD2013a(2002) height",
10013+
dbContext);
10014+
auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
10015+
ASSERT_TRUE(src != nullptr);
10016+
10017+
auto objDest = createFromUserInput("NAD83(CSRS)v7 + CGVD2013a(2010) height",
10018+
dbContext);
10019+
auto dst = nn_dynamic_pointer_cast<CRS>(objDest);
10020+
ASSERT_TRUE(dst != nullptr);
10021+
10022+
auto ctxt = CoordinateOperationContext::create(
10023+
AuthorityFactory::create(dbContext, std::string()), nullptr, 0);
10024+
ctxt->setSpatialCriterion(
10025+
CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
10026+
ctxt->setGridAvailabilityUse(
10027+
CoordinateOperationContext::GridAvailabilityUse::
10028+
IGNORE_GRID_AVAILABILITY);
10029+
auto list = CoordinateOperationFactory::create()->createOperations(
10030+
NN_NO_CHECK(src), NN_NO_CHECK(dst), ctxt);
10031+
ASSERT_GE(list.size(), 1U);
10032+
EXPECT_FALSE(list[0]->hasBallparkTransformation());
10033+
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
10034+
"+proj=pipeline "
10035+
"+step +proj=axisswap +order=2,1 "
10036+
"+step +proj=unitconvert +xy_in=deg +xy_out=rad "
10037+
"+step +proj=push +v_1 +v_2 "
10038+
"+step +proj=cart +ellps=GRS80 "
10039+
"+step +inv +proj=deformation +dt=-8 "
10040+
"+grids=ca_nrc_NAD83v70VG.tif +ellps=GRS80 "
10041+
"+step +inv +proj=cart +ellps=GRS80 "
10042+
"+step +proj=pop +v_1 +v_2 "
10043+
"+step +proj=unitconvert +xy_in=rad +xy_out=deg "
10044+
"+step +proj=axisswap +order=2,1");
10045+
}

0 commit comments

Comments
 (0)