LCOV - code coverage report
Current view: top level - autotest/cpp - test_osr_ct.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 205 205 100.0 %
Date: 2024-11-21 22:18:42 Functions: 39 39 100.0 %

          Line data    Source code
       1             : ///////////////////////////////////////////////////////////////////////////////
       2             : //
       3             : // Project:  C++ Test Suite for GDAL/OGR
       4             : // Purpose:  Test coordinate transformations. Ported from osr/osr_ct.py.
       5             : // Author:   Mateusz Loskot <mateusz@loskot.net>
       6             : //
       7             : ///////////////////////////////////////////////////////////////////////////////
       8             : // Copyright (c) 2006, Mateusz Loskot <mateusz@loskot.net>
       9             : /*
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal_unit_test.h"
      14             : 
      15             : #include "cpl_conv.h"
      16             : #include "cpl_error.h"
      17             : #include "ogr_api.h"
      18             : #include "ogr_srs_api.h"
      19             : #include "ogr_spatialref.h"
      20             : 
      21             : #include <algorithm>
      22             : #include <cmath>
      23             : #include <string>
      24             : 
      25             : #include "gtest_include.h"
      26             : 
      27             : namespace
      28             : {
      29             : 
      30             : // Common fixture with test data
      31             : struct test_osr_ct : public ::testing::Test
      32             : {
      33             :     OGRErr err_ = OGRERR_NONE;
      34             :     OGRSpatialReferenceH srs_utm_ = nullptr;
      35             :     OGRSpatialReferenceH srs_ll_ = nullptr;
      36             :     OGRCoordinateTransformationH ct_ = nullptr;
      37             : 
      38           9 :     void SetUp() override
      39             :     {
      40           9 :         srs_utm_ = OSRNewSpatialReference(nullptr);
      41           9 :         srs_ll_ = OSRNewSpatialReference(nullptr);
      42           9 :         OSRSetAxisMappingStrategy(srs_utm_, OAMS_TRADITIONAL_GIS_ORDER);
      43           9 :         OSRSetAxisMappingStrategy(srs_ll_, OAMS_TRADITIONAL_GIS_ORDER);
      44           9 :     }
      45             : 
      46           9 :     void TearDown() override
      47             :     {
      48           9 :         OSRDestroySpatialReference(srs_utm_);
      49           9 :         srs_utm_ = nullptr;
      50           9 :         OSRDestroySpatialReference(srs_ll_);
      51           9 :         srs_ll_ = nullptr;
      52           9 :         OCTDestroyCoordinateTransformation(ct_);
      53           9 :         ct_ = nullptr;
      54           9 :     }
      55             : };
      56             : 
      57           4 : TEST_F(test_osr_ct, basic)
      58             : {
      59           1 :     err_ = OSRSetUTM(srs_utm_, 11, TRUE);
      60           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      61             : 
      62           1 :     err_ = OSRSetWellKnownGeogCS(srs_utm_, "WGS84");
      63           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      64             : 
      65           1 :     err_ = OSRSetWellKnownGeogCS(srs_ll_, "WGS84");
      66           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      67             : 
      68           1 :     ct_ = OCTNewCoordinateTransformation(srs_ll_, srs_utm_);
      69           1 :     ASSERT_TRUE(nullptr != ct_);
      70             : }
      71             : 
      72             : // Actually perform a simple LL to UTM conversion
      73           4 : TEST_F(test_osr_ct, LL_to_UTM)
      74             : {
      75           1 :     err_ = OSRSetUTM(srs_utm_, 11, TRUE);
      76           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      77             : 
      78           1 :     err_ = OSRSetWellKnownGeogCS(srs_utm_, "WGS84");
      79           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      80             : 
      81           1 :     err_ = OSRSetWellKnownGeogCS(srs_ll_, "WGS84");
      82           1 :     ASSERT_EQ(err_, OGRERR_NONE);
      83             : 
      84           1 :     ct_ = OCTNewCoordinateTransformation(srs_ll_, srs_utm_);
      85           1 :     ASSERT_TRUE(nullptr != ct_);
      86             : 
      87           1 :     const int size = 1;
      88           1 :     double x[size] = {-117.5};
      89           1 :     double y[size] = {32.0};
      90           1 :     double z[size] = {0.0};
      91             : 
      92           1 :     ASSERT_EQ(OCTTransform(ct_, size, x, y, z), TRUE);
      93             : 
      94           1 :     EXPECT_NEAR(x[0], 452772.06, 0.01);
      95           1 :     EXPECT_NEAR(y[0], 3540544.89, 0.01);
      96           1 :     EXPECT_NEAR(z[0], 0.0, 0.01);
      97             : }
      98             : 
      99             : // Transform an OGR geometry.
     100             : // This is mostly aimed at ensuring that the OGRCoordinateTransformation
     101             : // target SRS isn't deleted till the output geometry which also
     102             : // uses it is deleted.
     103           4 : TEST_F(test_osr_ct, OGR_G_Transform)
     104             : {
     105           1 :     err_ = OSRSetUTM(srs_utm_, 11, TRUE);
     106           1 :     ASSERT_EQ(err_, OGRERR_NONE);
     107             : 
     108           1 :     err_ = OSRSetWellKnownGeogCS(srs_utm_, "WGS84");
     109           1 :     ASSERT_EQ(err_, OGRERR_NONE);
     110             : 
     111           1 :     err_ = OSRSetWellKnownGeogCS(srs_ll_, "WGS84");
     112           1 :     ASSERT_EQ(err_, OGRERR_NONE);
     113             : 
     114           1 :     ct_ = OCTNewCoordinateTransformation(srs_ll_, srs_utm_);
     115           1 :     ASSERT_TRUE(nullptr != ct_);
     116             : 
     117           1 :     const char *wkt = "POINT(-117.5 32.0)";
     118           1 :     OGRGeometryH geom = nullptr;
     119           1 :     err_ = OGR_G_CreateFromWkt((char **)&wkt, nullptr, &geom);
     120           1 :     EXPECT_EQ(OGRERR_NONE, err_);
     121           1 :     EXPECT_TRUE(nullptr != geom);
     122           1 :     if (geom)
     123             :     {
     124           1 :         err_ = OGR_G_Transform(geom, ct_);
     125           1 :         ASSERT_EQ(err_, OGRERR_NONE);
     126             : 
     127           1 :         OGRSpatialReferenceH srs = nullptr;
     128           1 :         srs = OGR_G_GetSpatialReference(geom);
     129             : 
     130           1 :         char *wktSrs = nullptr;
     131           1 :         err_ = OSRExportToPrettyWkt(srs, &wktSrs, FALSE);
     132           1 :         EXPECT_TRUE(nullptr != wktSrs);
     133           1 :         if (wktSrs)
     134             :         {
     135           2 :             std::string pretty(wktSrs);
     136           2 :             EXPECT_EQ(pretty.substr(0, 6), std::string("PROJCS"));
     137             :         }
     138           1 :         CPLFree(wktSrs);
     139           1 :         OGR_G_DestroyGeometry(geom);
     140             :     }
     141             : }
     142             : 
     143             : // Test OGRCoordinateTransformation::GetInverse()
     144           4 : TEST_F(test_osr_ct, GetInverse)
     145             : {
     146           1 :     OGRSpatialReference oSRSSource;
     147           1 :     oSRSSource.SetAxisMappingStrategy(OAMS_AUTHORITY_COMPLIANT);
     148           1 :     oSRSSource.importFromEPSG(4267);
     149             : 
     150           1 :     OGRSpatialReference oSRSTarget;
     151           1 :     oSRSTarget.SetAxisMappingStrategy(OAMS_AUTHORITY_COMPLIANT);
     152           1 :     oSRSTarget.importFromEPSG(4269);
     153             : 
     154             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     155           1 :         OGRCreateCoordinateTransformation(&oSRSSource, &oSRSTarget));
     156           1 :     ASSERT_TRUE(poCT != nullptr);
     157           1 :     ASSERT_TRUE(poCT->GetSourceCS() != nullptr);
     158           1 :     ASSERT_TRUE(poCT->GetSourceCS()->IsSame(&oSRSSource));
     159           1 :     ASSERT_TRUE(poCT->GetTargetCS() != nullptr);
     160           1 :     ASSERT_TRUE(poCT->GetTargetCS()->IsSame(&oSRSTarget));
     161             : 
     162             :     auto poInverse =
     163           1 :         std::unique_ptr<OGRCoordinateTransformation>(poCT->GetInverse());
     164           1 :     ASSERT_TRUE(poInverse != nullptr);
     165           1 :     ASSERT_TRUE(poInverse->GetSourceCS() != nullptr);
     166           1 :     ASSERT_TRUE(poInverse->GetSourceCS()->IsSame(&oSRSTarget));
     167           1 :     ASSERT_TRUE(poInverse->GetTargetCS() != nullptr);
     168           1 :     ASSERT_TRUE(poInverse->GetTargetCS()->IsSame(&oSRSSource));
     169             : 
     170           1 :     double x = 40;
     171           1 :     double y = -100;
     172           1 :     ASSERT_TRUE(poCT->Transform(1, &x, &y));
     173             :     // Check that the transformed point is different but not too far
     174           1 :     EXPECT_TRUE(fabs(x - 40) > 1e-10);
     175           1 :     EXPECT_TRUE(fabs(y - -100) > 1e-10);
     176           1 :     EXPECT_NEAR(x, 40, 1e-3);
     177           1 :     EXPECT_NEAR(y, -100, 1e-3);
     178           1 :     const double xTransformed = x;
     179           1 :     const double yTransformed = y;
     180             : 
     181           1 :     poCT.reset();
     182             : 
     183             :     // Check that the transformed point with the inverse transformation
     184             :     // matches the source
     185           1 :     ASSERT_TRUE(poInverse->Transform(1, &x, &y));
     186           1 :     EXPECT_NEAR(x, 40, 1e-8);
     187           1 :     EXPECT_NEAR(y, -100, 1e-8);
     188             : 
     189             :     auto poInvOfInv =
     190           1 :         std::unique_ptr<OGRCoordinateTransformation>(poInverse->GetInverse());
     191           1 :     ASSERT_TRUE(poInvOfInv != nullptr);
     192           1 :     ASSERT_TRUE(poInvOfInv->GetSourceCS() != nullptr);
     193           1 :     ASSERT_TRUE(poInvOfInv->GetSourceCS()->IsSame(&oSRSSource));
     194           1 :     ASSERT_TRUE(poInvOfInv->GetTargetCS() != nullptr);
     195           1 :     ASSERT_TRUE(poInvOfInv->GetTargetCS()->IsSame(&oSRSTarget));
     196           1 :     ASSERT_TRUE(poInvOfInv->Transform(1, &x, &y));
     197             :     // Check that the transformed point is different but not too far
     198           1 :     EXPECT_NEAR(x, xTransformed, 1e-8);
     199           1 :     EXPECT_NEAR(y, yTransformed, 1e-8);
     200             : }
     201             : 
     202             : // Test OGRCoordinateTransformation::GetInverse() with a specified coordinate
     203             : // operation
     204           4 : TEST_F(test_osr_ct, GetInverse_with_ct)
     205             : {
     206           1 :     OGRCoordinateTransformationOptions options;
     207           1 :     options.SetCoordinateOperation("+proj=affine +xoff=10", false);
     208             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     209           1 :         OGRCreateCoordinateTransformation(nullptr, nullptr, options));
     210           1 :     ASSERT_TRUE(poCT != nullptr);
     211             : 
     212             :     auto poInverse =
     213           1 :         std::unique_ptr<OGRCoordinateTransformation>(poCT->GetInverse());
     214           1 :     ASSERT_TRUE(poInverse != nullptr);
     215           1 :     ASSERT_TRUE(poInverse->GetSourceCS() == nullptr);
     216           1 :     ASSERT_TRUE(poInverse->GetTargetCS() == nullptr);
     217             : 
     218           1 :     poCT.reset();
     219             : 
     220           1 :     double x = 100;
     221           1 :     double y = 200;
     222           1 :     ASSERT_TRUE(poInverse->Transform(1, &x, &y));
     223           1 :     EXPECT_NEAR(x, 90, 1e-12);
     224           1 :     EXPECT_NEAR(y, 200.0, 1e-12);
     225             : }
     226             : 
     227             : // Test OGRCoordinateTransformation::Clone()
     228           3 : static void test_clone(OGRCoordinateTransformation *poCT,
     229             :                        OGRSpatialReference *poSRSSource,
     230             :                        OGRSpatialReference *poSRSTarget, const double xSrc,
     231             :                        const double ySrc)
     232             : {
     233           3 :     ASSERT_TRUE(poCT != nullptr);
     234           3 :     ASSERT_TRUE((poCT->GetSourceCS() == nullptr) == (poSRSSource == nullptr));
     235           3 :     if (poSRSSource != nullptr)
     236             :     {
     237           2 :         ASSERT_TRUE(poCT->GetSourceCS()->IsSame(poSRSSource));
     238             :     }
     239           3 :     ASSERT_TRUE((poCT->GetTargetCS() == nullptr) == (poSRSTarget == nullptr));
     240           3 :     if (poSRSTarget != nullptr)
     241             :     {
     242           2 :         ASSERT_TRUE(poCT->GetTargetCS()->IsSame(poSRSTarget));
     243             :     }
     244           3 :     double x = xSrc;
     245           3 :     double y = ySrc;
     246           3 :     ASSERT_TRUE(poCT->Transform(1, &x, &y));
     247           3 :     const double xTransformed = x;
     248           3 :     const double yTransformed = y;
     249             : 
     250           3 :     auto poClone = std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());
     251           3 :     ASSERT_TRUE(poClone != nullptr);
     252           3 :     ASSERT_TRUE((poClone->GetSourceCS() == nullptr) ==
     253             :                 (poSRSSource == nullptr));
     254           3 :     if (poSRSSource != nullptr)
     255             :     {
     256           2 :         ASSERT_TRUE(poClone->GetSourceCS()->IsSame(poSRSSource));
     257             :     }
     258           3 :     ASSERT_TRUE((poClone->GetTargetCS() == nullptr) ==
     259             :                 (poSRSTarget == nullptr));
     260           3 :     if (poSRSTarget != nullptr)
     261             :     {
     262           2 :         ASSERT_TRUE(poClone->GetTargetCS()->IsSame(poSRSTarget));
     263             :     }
     264           3 :     x = xSrc;
     265           3 :     y = ySrc;
     266           3 :     ASSERT_TRUE(poClone->Transform(1, &x, &y));
     267           3 :     EXPECT_NEAR(x, xTransformed, 1e-15);
     268           3 :     EXPECT_NEAR(y, yTransformed, 1e-15);
     269             : }
     270             : 
     271             : // Test OGRCoordinateTransformation::Clone() with usual case
     272           4 : TEST_F(test_osr_ct, Clone)
     273             : {
     274           2 :     OGRSpatialReference oSRSSource;
     275           1 :     oSRSSource.importFromEPSG(4267);
     276           1 :     oSRSSource.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     277             : 
     278           2 :     OGRSpatialReference oSRSTarget;
     279           1 :     oSRSTarget.importFromEPSG(4269);
     280           1 :     oSRSTarget.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     281             : 
     282             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     283           2 :         OGRCreateCoordinateTransformation(&oSRSSource, &oSRSTarget));
     284             : 
     285           1 :     test_clone(poCT.get(), &oSRSSource, &oSRSTarget, 44, -60);
     286           1 : }
     287             : 
     288             : // Test OGRCoordinateTransformation::Clone() with a specified coordinate
     289             : // operation
     290           4 : TEST_F(test_osr_ct, Clone_with_ct)
     291             : {
     292           2 :     OGRCoordinateTransformationOptions options;
     293           1 :     options.SetCoordinateOperation("+proj=affine +xoff=10", false);
     294             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     295           2 :         OGRCreateCoordinateTransformation(nullptr, nullptr, options));
     296             : 
     297           1 :     test_clone(poCT.get(), nullptr, nullptr, 90, 200);
     298           1 : }
     299             : 
     300             : // Test OGRCoordinateTransformation::Clone() with WebMercator->WGS84 special
     301             : // case
     302           4 : TEST_F(test_osr_ct, Clone_WebMercator_to_WGS84)
     303             : {
     304           2 :     OGRSpatialReference oSRSSource;
     305           1 :     oSRSSource.importFromEPSG(3857);
     306           1 :     oSRSSource.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     307             : 
     308           2 :     OGRSpatialReference oSRSTarget;
     309           1 :     oSRSTarget.SetWellKnownGeogCS("WGS84");
     310           1 :     oSRSTarget.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     311             : 
     312             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     313           2 :         OGRCreateCoordinateTransformation(&oSRSSource, &oSRSTarget));
     314             : 
     315           1 :     test_clone(poCT.get(), &oSRSSource, &oSRSTarget, 44, -60);
     316           1 : }
     317             : 
     318             : // Test OGRCoordinateTransformation in pure "C" API
     319             : // OCTClone/OCTGetSourceCS/OCTGetTargetCS/OCTGetInverse
     320           4 : TEST_F(test_osr_ct, OGRCoordinateTransformation_C_API)
     321             : {
     322           1 :     OGRSpatialReferenceH hSource = OSRNewSpatialReference(nullptr);
     323           1 :     OGRSpatialReferenceH hTarget = OSRNewSpatialReference(nullptr);
     324           1 :     EXPECT_TRUE(hSource != nullptr);
     325           1 :     EXPECT_TRUE(hTarget != nullptr);
     326           1 :     if (hSource && hTarget)
     327             :     {
     328           1 :         EXPECT_TRUE(OGRERR_NONE == OSRImportFromEPSG(hSource, 32637));
     329           1 :         EXPECT_TRUE(OGRERR_NONE == OSRSetWellKnownGeogCS(hTarget, "WGS84"));
     330             :         OGRCoordinateTransformationH hTransform =
     331           1 :             OCTNewCoordinateTransformation(hSource, hTarget);
     332           1 :         EXPECT_TRUE(hTransform != nullptr);
     333           1 :         if (hTransform)
     334             :         {
     335           1 :             OGRCoordinateTransformationH hClone = OCTClone(hTransform);
     336           1 :             EXPECT_TRUE(hClone != nullptr);
     337             : 
     338             :             OGRCoordinateTransformationH hInvTransform =
     339           1 :                 OCTGetInverse(hTransform);
     340           1 :             EXPECT_TRUE(hInvTransform != nullptr);
     341           1 :             if (hClone && hInvTransform)
     342             :             {
     343             :                 OGRSpatialReferenceH hSourceInternal =
     344           1 :                     OCTGetSourceCS(hTransform);
     345           1 :                 EXPECT_TRUE(hSourceInternal != nullptr);
     346             :                 OGRSpatialReferenceH hTargetInternal =
     347           1 :                     OCTGetTargetCS(hTransform);
     348           1 :                 EXPECT_TRUE(hTargetInternal != nullptr);
     349             : 
     350           1 :                 if (hSourceInternal)
     351             :                 {
     352           1 :                     EXPECT_TRUE(OSRIsSame(hSource, hSourceInternal));
     353             :                 }
     354           1 :                 if (hTargetInternal)
     355             :                 {
     356           1 :                     EXPECT_TRUE(OSRIsSame(hTarget, hTargetInternal));
     357             :                 }
     358             :             }
     359             : 
     360           1 :             OCTDestroyCoordinateTransformation(hInvTransform);
     361           1 :             OCTDestroyCoordinateTransformation(hClone);
     362             :         }
     363           1 :         OCTDestroyCoordinateTransformation(hTransform);
     364             :     }
     365           1 :     OSRDestroySpatialReference(hSource);
     366           1 :     OSRDestroySpatialReference(hTarget);
     367           1 : }
     368             : }  // namespace

Generated by: LCOV version 1.14