Skip to content

Commit 08a2bf5

Browse files
committed
OGR_CT: handle point motion operations (PROJ >= 9.4)
1 parent f7d9755 commit 08a2bf5

File tree

4 files changed

+67
-3
lines changed

4 files changed

+67
-3
lines changed

autotest/osr/osr_ct.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,3 +768,35 @@ def test_osr_ct_OGR_CT_PREFER_OFFICIAL_SRS_DEF():
768768
x, y, _ = ct.TransformPoint(826158.063, 2405844.125, 0)
769769
assert abs(x - 9.867) < 0.001, x
770770
assert abs(y - 71.125) < 0.001, y
771+
772+
773+
###############################################################################
774+
# Test NAD83(CSRS)v7 change of epoch
775+
776+
777+
@pytest.mark.require_proj(9, 4)
778+
def test_osr_ct_point_motion_operation():
779+
780+
s = osr.SpatialReference()
781+
s.ImportFromEPSG(8254) # NAD83(CSRS)v7 3D
782+
s.SetCoordinateEpoch(2002)
783+
784+
t = osr.SpatialReference()
785+
t.ImportFromEPSG(8254) # NAD83(CSRS)v7 3D
786+
t.SetCoordinateEpoch(2010)
787+
788+
ct = osr.CoordinateTransformation(s, t)
789+
x, y, z = ct.TransformPoint(60.5, -79.5)
790+
assert abs(x - 60.49999994) < 1e-8, x
791+
assert abs(y - -79.49999963) < 1e-8, y
792+
assert abs(z - 0.060) < 1e-3, z
793+
794+
t = osr.SpatialReference()
795+
t.ImportFromEPSG(22717) # "NAD83(CSRS)v7 / UTM zone 17N"
796+
t.SetCoordinateEpoch(2010)
797+
798+
ct = osr.CoordinateTransformation(s, t)
799+
x, y, z = ct.TransformPoint(60.5, -79.5)
800+
assert abs(x - 582395.993) < 1e-3, x
801+
assert abs(y - 6708035.973) < 1e-3, y
802+
assert abs(z - 0.060) < 1e-3, z

autotest/proj_grids/README.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
* ``conus`` is the "official" NADCON4 conus NAD27->NAD84 file in CTable2 format
22
* ``egm96_15_extract.gtx`` is an extract generated with ``gdal_translate /usr/share/proj/egm96_15.gtx ../autotest/proj_grids/egm96_15_extract.gtx -srcwin 234 233 3 3``
3+
* ``ca_nrc_NAD83v70VG.tif`` is an extract generated with ``gdal_translate ~/proj/PROJ-data/ca_nrc/ca_nrc_NAD83v70VG.tif ca_nrc_NAD83v70VG.tif -b 1 -b 2 -b 3 -co compress=deflate -projwin -80 61 -79 60``
1.16 KB
Binary file not shown.

ogr/ogrct.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,24 +1470,35 @@ int OGRProjCT::Initialize(const OGRSpatialReference *poSourceIn,
14701470
bSourceLatLong = CPL_TO_BOOL(poSRSSource->IsGeographic());
14711471
bSourceIsDynamicCRS = poSRSSource->IsDynamic();
14721472
dfSourceCoordinateEpoch = poSRSSource->GetCoordinateEpoch();
1473+
if (!bSourceIsDynamicCRS && dfSourceCoordinateEpoch > 0)
1474+
{
1475+
bSourceIsDynamicCRS = poSRSSource->HasPointMotionOperation();
1476+
}
14731477
poSRSSource->GetAxis(nullptr, 0, &m_eSourceFirstAxisOrient);
14741478
}
14751479
if (poSRSTarget)
14761480
{
14771481
bTargetLatLong = CPL_TO_BOOL(poSRSTarget->IsGeographic());
14781482
bTargetIsDynamicCRS = poSRSTarget->IsDynamic();
14791483
dfTargetCoordinateEpoch = poSRSTarget->GetCoordinateEpoch();
1484+
if (!bTargetIsDynamicCRS && dfTargetCoordinateEpoch > 0)
1485+
{
1486+
bTargetIsDynamicCRS = poSRSTarget->HasPointMotionOperation();
1487+
}
14801488
poSRSTarget->GetAxis(nullptr, 0, &m_eTargetFirstAxisOrient);
14811489
}
14821490

1491+
#if PROJ_VERSION_MAJOR < 9 || \
1492+
(PROJ_VERSION_MAJOR == 9 && PROJ_VERSION_MINOR < 4)
14831493
if (bSourceIsDynamicCRS && bTargetIsDynamicCRS &&
14841494
dfSourceCoordinateEpoch > 0 && dfTargetCoordinateEpoch > 0 &&
14851495
dfSourceCoordinateEpoch != dfTargetCoordinateEpoch)
14861496
{
14871497
CPLError(CE_Warning, CPLE_AppDefined,
1488-
"Coordinate transformation between different epochs are "
1489-
"not currently supported");
1498+
"Coordinate transformation between different epochs only"
1499+
"supported since PROJ 9.4");
14901500
}
1501+
#endif
14911502

14921503
/* -------------------------------------------------------------------- */
14931504
/* Setup source and target translations to radians for lat/long */
@@ -1659,6 +1670,24 @@ int OGRProjCT::Initialize(const OGRSpatialReference *poSourceIn,
16591670
options.d->bOnlyBest ? "YES" : "NO");
16601671
}
16611672
#endif
1673+
1674+
#if PROJ_VERSION_MAJOR > 9 || \
1675+
(PROJ_VERSION_MAJOR == 9 && PROJ_VERSION_MINOR >= 4)
1676+
if (bSourceIsDynamicCRS && dfSourceCoordinateEpoch > 0 &&
1677+
bTargetIsDynamicCRS && dfTargetCoordinateEpoch > 0)
1678+
{
1679+
auto srcCM = proj_coordinate_metadata_create(
1680+
ctx, srcCRS, dfSourceCoordinateEpoch);
1681+
proj_destroy(srcCRS);
1682+
srcCRS = srcCM;
1683+
1684+
auto targetCM = proj_coordinate_metadata_create(
1685+
ctx, targetCRS, dfTargetCoordinateEpoch);
1686+
proj_destroy(targetCRS);
1687+
targetCRS = targetCM;
1688+
}
1689+
#endif
1690+
16621691
m_pj = proj_create_crs_to_crs_from_pj(ctx, srcCRS, targetCRS, area,
16631692
aosOptions.List());
16641693
proj_destroy(srcCRS);
@@ -1694,7 +1723,9 @@ int OGRProjCT::Initialize(const OGRSpatialReference *poSourceIn,
16941723
#endif
16951724
}
16961725

1697-
if (options.d->osCoordOperation.empty() && poSRSSource && poSRSTarget)
1726+
if (options.d->osCoordOperation.empty() && poSRSSource && poSRSTarget &&
1727+
(dfSourceCoordinateEpoch == 0 || dfTargetCoordinateEpoch == 0 ||
1728+
dfSourceCoordinateEpoch == dfTargetCoordinateEpoch))
16981729
{
16991730
// Determine if we can skip the transformation completely.
17001731
const char *const apszOptionsIsSame[] = {"CRITERION=EQUIVALENT",

0 commit comments

Comments
 (0)