LCOV - code coverage report
Current view: top level - autotest/cpp - test_alg.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 267 276 96.7 %
Date: 2025-01-18 12:42:00 Functions: 49 50 98.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL algorithms
       4             :  * Purpose:  Test alg
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2016, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include <array>
      14             : 
      15             : #include "gdal_unit_test.h"
      16             : 
      17             : #include "cpl_conv.h"
      18             : 
      19             : #include "gdal_alg.h"
      20             : #include "gdalwarper.h"
      21             : #include "gdal_priv.h"
      22             : 
      23             : #include "gtest_include.h"
      24             : 
      25             : #include "test_data.h"
      26             : 
      27             : namespace
      28             : {
      29             : // Common fixture with test data
      30             : struct test_alg : public ::testing::Test
      31             : {
      32             :     std::string data_;
      33             : 
      34          12 :     test_alg()
      35          12 :     {
      36             :         // Compose data path for test group
      37          12 :         data_ = tut::common::data_basedir;
      38          12 :     }
      39             : };
      40             : 
      41             : typedef struct
      42             : {
      43             :     double dfLevel;
      44             :     int nPoints;
      45             :     double x;
      46             :     double y;
      47             : } writeCbkData;
      48             : 
      49           0 : static CPLErr writeCbk(double dfLevel, int nPoints, double *padfX,
      50             :                        double *padfY, void *userData)
      51             : {
      52           0 :     writeCbkData *data = (writeCbkData *)userData;
      53           0 :     data->dfLevel = dfLevel;
      54           0 :     data->nPoints = nPoints;
      55           0 :     if (nPoints == 1)
      56             :     {
      57           0 :         data->x = padfX[0];
      58           0 :         data->y = padfY[0];
      59             :     }
      60           0 :     return CE_None;
      61             : }
      62             : 
      63             : // Dummy test
      64           4 : TEST_F(test_alg, GDAL_CG_FeedLine_dummy)
      65             : {
      66             :     writeCbkData data;
      67           1 :     memset(&data, 0, sizeof(data));
      68             :     GDALContourGeneratorH hCG =
      69           1 :         GDAL_CG_Create(1, 1, FALSE, 0, 1, 0, writeCbk, &data);
      70           1 :     double scanline[] = {0};
      71           1 :     EXPECT_EQ(GDAL_CG_FeedLine(hCG, scanline), CE_None);
      72           1 :     EXPECT_EQ(data.dfLevel, 0);
      73           1 :     EXPECT_EQ(data.nPoints, 0);
      74           1 :     EXPECT_DOUBLE_EQ(data.x, 0.0);
      75           1 :     EXPECT_DOUBLE_EQ(data.y, 0.0);
      76           1 :     GDAL_CG_Destroy(hCG);
      77           1 : }
      78             : 
      79             : // GDALWarpResolveWorkingDataType: default type
      80           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_default_type)
      81             : {
      82           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
      83           1 :     GDALWarpResolveWorkingDataType(psOptions);
      84           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
      85           1 :     GDALDestroyWarpOptions(psOptions);
      86           1 : }
      87             : 
      88             : // GDALWarpResolveWorkingDataType: do not change user specified type
      89           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_keep_user_type)
      90             : {
      91           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
      92           1 :     psOptions->eWorkingDataType = GDT_CFloat64;
      93           1 :     GDALWarpResolveWorkingDataType(psOptions);
      94           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat64);
      95           1 :     GDALDestroyWarpOptions(psOptions);
      96           1 : }
      97             : 
      98             : // GDALWarpResolveWorkingDataType: effect of padfSrcNoDataReal
      99           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfSrcNoDataReal)
     100             : {
     101           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     102           1 :     psOptions->nBandCount = 1;
     103           1 :     psOptions->padfSrcNoDataReal =
     104           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     105           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     106           1 :     GDALWarpResolveWorkingDataType(psOptions);
     107           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     108             : 
     109           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     110           1 :     psOptions->padfSrcNoDataReal[0] = -1.0;
     111           1 :     GDALWarpResolveWorkingDataType(psOptions);
     112           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Int16);
     113             : 
     114           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     115           1 :     psOptions->padfSrcNoDataReal[0] = 2.0;
     116           1 :     GDALWarpResolveWorkingDataType(psOptions);
     117           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     118             : 
     119           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     120           1 :     psOptions->padfSrcNoDataReal[0] = 256.0;
     121           1 :     GDALWarpResolveWorkingDataType(psOptions);
     122           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_UInt16);
     123             : 
     124           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     125           1 :     psOptions->padfSrcNoDataReal[0] = 2.5;
     126           1 :     GDALWarpResolveWorkingDataType(psOptions);
     127           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float32);
     128             : 
     129           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     130           1 :     psOptions->padfSrcNoDataReal[0] = 2.12345678;
     131           1 :     GDALWarpResolveWorkingDataType(psOptions);
     132           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float64);
     133             : 
     134           1 :     GDALDestroyWarpOptions(psOptions);
     135           1 : }
     136             : 
     137             : // GDALWarpResolveWorkingDataType: effect of padfSrcNoDataReal
     138           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfSrcNoDataReal_with_band)
     139             : {
     140             :     GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
     141           2 :                                   ->Create("", 1, 1, 1, GDT_Byte, nullptr));
     142           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     143             :     // False-positive: hSrcDS is no longer used after GDALDestroyWarpOptions()
     144             :     // coverity[escape]
     145           1 :     psOptions->hSrcDS = GDALDataset::ToHandle(poDS.get());
     146           1 :     psOptions->nBandCount = 1;
     147           1 :     psOptions->panSrcBands =
     148           1 :         static_cast<int *>(CPLMalloc(psOptions->nBandCount * sizeof(int)));
     149           1 :     psOptions->panSrcBands[0] = 1;
     150           1 :     psOptions->padfSrcNoDataReal =
     151           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     152           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     153           1 :     GDALWarpResolveWorkingDataType(psOptions);
     154           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     155             : 
     156           1 :     psOptions->padfSrcNoDataReal[0] = -1.0;
     157           1 :     GDALWarpResolveWorkingDataType(psOptions);
     158           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     159             : 
     160           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     161           1 :     psOptions->padfSrcNoDataReal[0] = 2.0;
     162           1 :     GDALWarpResolveWorkingDataType(psOptions);
     163           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     164             : 
     165           1 :     GDALDestroyWarpOptions(psOptions);
     166           1 : }
     167             : 
     168             : // GDALWarpResolveWorkingDataType: effect of padfSrcNoDataImag
     169           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfSrcNoDataImag)
     170             : {
     171           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     172           1 :     psOptions->nBandCount = 1;
     173           1 :     psOptions->padfSrcNoDataReal =
     174           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     175           1 :     psOptions->padfSrcNoDataImag =
     176           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     177           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     178           1 :     psOptions->padfSrcNoDataImag[0] = 0.0;
     179           1 :     GDALWarpResolveWorkingDataType(psOptions);
     180           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     181             : 
     182           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     183           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     184           1 :     psOptions->padfSrcNoDataImag[0] = 1.0;
     185           1 :     GDALWarpResolveWorkingDataType(psOptions);
     186             :     // Could probably be CInt16
     187           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CInt32);
     188             : 
     189           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     190           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     191           1 :     psOptions->padfSrcNoDataImag[0] = 1.5;
     192           1 :     GDALWarpResolveWorkingDataType(psOptions);
     193           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat32);
     194             : 
     195           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     196           1 :     psOptions->padfSrcNoDataReal[0] = 0.0;
     197           1 :     psOptions->padfSrcNoDataImag[0] = 2.12345678;
     198           1 :     GDALWarpResolveWorkingDataType(psOptions);
     199           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat64);
     200             : 
     201           1 :     GDALDestroyWarpOptions(psOptions);
     202           1 : }
     203             : 
     204             : // GDALWarpResolveWorkingDataType: effect of padfDstNoDataReal
     205           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfDstNoDataReal)
     206             : {
     207           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     208           1 :     psOptions->nBandCount = 1;
     209           1 :     psOptions->padfDstNoDataReal =
     210           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     211           1 :     psOptions->padfDstNoDataReal[0] = 0.0;
     212           1 :     GDALWarpResolveWorkingDataType(psOptions);
     213           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     214             : 
     215           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     216           1 :     psOptions->padfDstNoDataReal[0] = -1.0;
     217           1 :     GDALWarpResolveWorkingDataType(psOptions);
     218           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Int16);
     219             : 
     220           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     221           1 :     psOptions->padfDstNoDataReal[0] = 2.0;
     222           1 :     GDALWarpResolveWorkingDataType(psOptions);
     223           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     224             : 
     225           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     226           1 :     psOptions->padfDstNoDataReal[0] = 256.0;
     227           1 :     GDALWarpResolveWorkingDataType(psOptions);
     228           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_UInt16);
     229             : 
     230           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     231           1 :     psOptions->padfDstNoDataReal[0] = 2.5;
     232           1 :     GDALWarpResolveWorkingDataType(psOptions);
     233           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float32);
     234             : 
     235           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     236           1 :     psOptions->padfDstNoDataReal[0] = 2.12345678;
     237           1 :     GDALWarpResolveWorkingDataType(psOptions);
     238           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float64);
     239             : 
     240           1 :     GDALDestroyWarpOptions(psOptions);
     241           1 : }
     242             : 
     243             : // GDALWarpResolveWorkingDataType: effect of padfDstNoDataImag
     244           4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfDstNoDataImag)
     245             : {
     246           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     247           1 :     psOptions->nBandCount = 1;
     248           1 :     psOptions->padfDstNoDataReal =
     249           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     250           1 :     psOptions->padfDstNoDataImag =
     251           1 :         static_cast<double *>(CPLMalloc(sizeof(double)));
     252           1 :     psOptions->padfDstNoDataReal[0] = 0.0;
     253           1 :     psOptions->padfDstNoDataImag[0] = 0.0;
     254           1 :     GDALWarpResolveWorkingDataType(psOptions);
     255           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
     256             : 
     257           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     258           1 :     psOptions->padfDstNoDataReal[0] = 0.0;
     259           1 :     psOptions->padfDstNoDataImag[0] = 1.0;
     260           1 :     GDALWarpResolveWorkingDataType(psOptions);
     261             :     // Could probably be CInt16
     262           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CInt32);
     263             : 
     264           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     265           1 :     psOptions->padfDstNoDataImag[0] = 0.0;
     266           1 :     psOptions->padfDstNoDataImag[0] = 1.5;
     267           1 :     GDALWarpResolveWorkingDataType(psOptions);
     268           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat32);
     269             : 
     270           1 :     psOptions->eWorkingDataType = GDT_Unknown;
     271           1 :     psOptions->padfDstNoDataImag[0] = 0.0;
     272           1 :     psOptions->padfDstNoDataImag[0] = 2.12345678;
     273           1 :     GDALWarpResolveWorkingDataType(psOptions);
     274           1 :     EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat64);
     275             : 
     276           1 :     GDALDestroyWarpOptions(psOptions);
     277           1 : }
     278             : 
     279             : // Test GDALAutoCreateWarpedVRT() with creation of an alpha band
     280           4 : TEST_F(test_alg, GDALAutoCreateWarpedVRT_alpha_band)
     281             : {
     282             :     GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
     283           1 :                                   ->Create("", 1, 1, 1, GDT_Byte, nullptr));
     284           1 :     poDS->SetProjection(SRS_WKT_WGS84_LAT_LONG);
     285           1 :     double adfGeoTransform[6] = {10, 1, 0, 20, 0, -1};
     286           1 :     poDS->SetGeoTransform(adfGeoTransform);
     287           1 :     GDALWarpOptions *psOptions = GDALCreateWarpOptions();
     288           1 :     psOptions->nDstAlphaBand = 2;
     289             :     GDALDatasetH hWarpedVRT =
     290           1 :         GDALAutoCreateWarpedVRT(GDALDataset::ToHandle(poDS.get()), nullptr,
     291             :                                 nullptr, GRA_NearestNeighbour, 0.0, psOptions);
     292           1 :     ASSERT_TRUE(hWarpedVRT != nullptr);
     293           1 :     ASSERT_EQ(GDALGetRasterCount(hWarpedVRT), 2);
     294           1 :     EXPECT_EQ(
     295             :         GDALGetRasterColorInterpretation(GDALGetRasterBand(hWarpedVRT, 2)),
     296             :         GCI_AlphaBand);
     297           1 :     GDALDestroyWarpOptions(psOptions);
     298           1 :     GDALClose(hWarpedVRT);
     299             : }
     300             : 
     301             : // Test GDALIsLineOfSightVisible() with single point dataset
     302           4 : TEST_F(test_alg, GDALIsLineOfSightVisible_single_point_dataset)
     303             : {
     304           1 :     auto const sizeX = 1;
     305           1 :     auto const sizeY = 1;
     306           1 :     auto const numBands = 1;
     307             :     GDALDatasetUniquePtr poDS(
     308             :         GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
     309           1 :             ->Create("", sizeX, sizeY, numBands, GDT_Int8, nullptr));
     310           1 :     ASSERT_TRUE(poDS != nullptr);
     311             : 
     312           1 :     int8_t val = 42;
     313           1 :     auto pBand = poDS->GetRasterBand(1);
     314           1 :     ASSERT_TRUE(pBand != nullptr);
     315           1 :     ASSERT_TRUE(poDS->RasterIO(GF_Write, 0, 0, 1, 1, &val, 1, 1, GDT_Int8, 1,
     316             :                                nullptr, 0, 0, 0, nullptr) == CE_None);
     317             :     // Both points below terrain
     318           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 0.0, 0, 0, 0.0, nullptr,
     319             :                                           nullptr, nullptr));
     320             :     // One point below terrain
     321           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 0.0, 0, 0, 43.0, nullptr,
     322             :                                           nullptr, nullptr));
     323             :     int xIntersection, yIntersection;
     324           1 :     int *pXIntersection = &xIntersection;
     325           1 :     int *pYIntersection = &yIntersection;
     326           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(
     327             :         pBand, 0, 0, 0.0, 0, 0, 43.0, pXIntersection, pYIntersection, nullptr));
     328           1 :     EXPECT_EQ(*pXIntersection, 0);
     329           1 :     EXPECT_EQ(*pYIntersection, 0);
     330             :     // Both points above terrain
     331           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 44.0, 0, 0, 43.0, nullptr,
     332             :                                          nullptr, nullptr));
     333           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 44.0, 0, 0, 43.0,
     334             :                                          pXIntersection, pYIntersection,
     335             :                                          nullptr));
     336             : }
     337             : 
     338             : // Test GDALIsLineOfSightVisible() with 10x10 default dataset
     339           4 : TEST_F(test_alg, GDALIsLineOfSightVisible_default_square_dataset)
     340             : {
     341           1 :     auto const sizeX = 10;
     342           1 :     auto const sizeY = 10;
     343           1 :     auto const numBands = 1;
     344             :     GDALDatasetUniquePtr poDS(
     345             :         GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
     346           1 :             ->Create("", sizeX, sizeY, numBands, GDT_Int8, nullptr));
     347           1 :     ASSERT_TRUE(poDS != nullptr);
     348             : 
     349           1 :     auto pBand = poDS->GetRasterBand(1);
     350           1 :     ASSERT_TRUE(pBand != nullptr);
     351             : 
     352           1 :     const int x1 = 1;
     353           1 :     const int y1 = 1;
     354           1 :     const int x2 = 2;
     355           1 :     const int y2 = 2;
     356             : 
     357             :     // Both points are above terrain.
     358           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x1, y1, 1.0, x2, y2, 1.0,
     359             :                                          nullptr, nullptr, nullptr));
     360             :     // Both points are above terrain, supply intersection.
     361             :     int xIntersection, yIntersection;
     362           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x1, y1, 1.0, x2, y2, 1.0,
     363             :                                          &xIntersection, &yIntersection,
     364             :                                          nullptr));
     365             :     // Flip the order, same result.
     366           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x2, y2, 1.0, x1, y1, 1.0,
     367             :                                          nullptr, nullptr, nullptr));
     368             : 
     369             :     // One point is below terrain.
     370           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, 1.0,
     371             :                                           nullptr, nullptr, nullptr));
     372           1 :     int *pXIntersection = &xIntersection;
     373           1 :     int *pYIntersection = &yIntersection;
     374           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, 1.0,
     375             :                                           pXIntersection, pYIntersection,
     376             :                                           nullptr));
     377           1 :     EXPECT_EQ(*pXIntersection, 1);
     378           1 :     EXPECT_EQ(*pYIntersection, 1);
     379             :     // Flip the order, same result.
     380           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x2, y2, -1.0, x1, y1, 1.0,
     381             :                                           pXIntersection, pYIntersection,
     382             :                                           nullptr));
     383           1 :     EXPECT_EQ(*pXIntersection, 2);
     384           1 :     EXPECT_EQ(*pYIntersection, 2);
     385             : 
     386             :     // Both points are below terrain.
     387           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, -1.0,
     388             :                                           nullptr, nullptr, nullptr));
     389             :     // Flip the order, same result.
     390           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x2, y2, -1.0, x1, y1, -1.0,
     391             :                                           nullptr, nullptr, nullptr));
     392             : }
     393             : 
     394             : // Test GDALIsLineOfSightVisible() through a mountain (not a unit test)
     395           4 : TEST_F(test_alg, GDALIsLineOfSightVisible_through_mountain)
     396             : {
     397           1 :     GDALAllRegister();
     398             : 
     399           1 :     const std::string path = data_ + SEP + "n43.dt0";
     400             :     const auto poDS = GDALDatasetUniquePtr(
     401           1 :         GDALDataset::FromHandle(GDALOpen(path.c_str(), GA_ReadOnly)));
     402           1 :     if (!poDS)
     403             :     {
     404           0 :         GTEST_SKIP() << "Cannot open " << path;
     405             :     }
     406             : 
     407           1 :     auto pBand = poDS->GetRasterBand(1);
     408           1 :     ASSERT_TRUE(pBand != nullptr);
     409             :     std::array<double, 6> geoFwdTransform;
     410           1 :     ASSERT_TRUE(poDS->GetGeoTransform(geoFwdTransform.data()) == CE_None);
     411             :     std::array<double, 6> geoInvTransform;
     412           1 :     ASSERT_TRUE(
     413             :         GDALInvGeoTransform(geoFwdTransform.data(), geoInvTransform.data()));
     414             : 
     415             :     // Check both sides of a mesa (north and south ends).
     416             :     // Top mesa at (x=8,y=58,alt=221)
     417           1 :     const double mesaLatTop = 43.5159;
     418           1 :     const double mesaLngTop = -79.9327;
     419             : 
     420             :     // Bottom is at (x=12,y=64,alt=199)
     421           1 :     const double mesaLatBottom = 43.4645;
     422           1 :     const double mesaLngBottom = -79.8985;
     423             : 
     424             :     // In between the two locations, the mesa reaches a local max altiude of 321.
     425             : 
     426             :     double dMesaTopX, dMesaTopY, dMesaBottomX, dMesaBottomY;
     427           1 :     GDALApplyGeoTransform(geoInvTransform.data(), mesaLngTop, mesaLatTop,
     428             :                           &dMesaTopX, &dMesaTopY);
     429           1 :     GDALApplyGeoTransform(geoInvTransform.data(), mesaLngBottom, mesaLatBottom,
     430             :                           &dMesaBottomX, &dMesaBottomY);
     431           1 :     const int iMesaTopX = static_cast<int>(dMesaTopX);
     432           1 :     const int iMesaTopY = static_cast<int>(dMesaTopY);
     433           1 :     const int iMesaBottomX = static_cast<int>(dMesaBottomX);
     434           1 :     const int iMesaBottomY = static_cast<int>(dMesaBottomY);
     435             : 
     436             :     // Both points are just above terrain, with terrain between.
     437           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 222,
     438             :                                           iMesaBottomX, iMesaBottomY, 199,
     439             :                                           nullptr, nullptr, nullptr));
     440             :     // Flip the order, same result.
     441           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaBottomX, iMesaBottomY,
     442             :                                           199, iMesaTopX, iMesaTopY, 222,
     443             :                                           nullptr, nullptr, nullptr));
     444             : 
     445             :     // Both points above terrain.
     446           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 322,
     447             :                                          iMesaBottomX, iMesaBottomY, 322,
     448             :                                          nullptr, nullptr, nullptr));
     449             : 
     450             :     // Both points below terrain.
     451           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 0,
     452             :                                           iMesaBottomX, iMesaBottomY, 0,
     453             :                                           nullptr, nullptr, nullptr));
     454             : 
     455             :     // Test negative slope bresenham diagonals across the whole raster.
     456             :     // Both high above terrain.
     457           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 460, 120, 120, 460,
     458             :                                          nullptr, nullptr, nullptr));
     459             :     // Both heights are 1m above in the corners, but middle terrain violates LOS.
     460           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 295, 120, 120, 183,
     461             :                                           nullptr, nullptr, nullptr));
     462             : 
     463             :     int xIntersection, yIntersection;
     464           1 :     int *pXIntersection = &xIntersection;
     465           1 :     int *pYIntersection = &yIntersection;
     466           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 295, 120, 120, 183,
     467             :                                           pXIntersection, pYIntersection,
     468             :                                           nullptr));
     469           1 :     EXPECT_EQ(*pXIntersection, 2);
     470           1 :     EXPECT_EQ(*pYIntersection, 2);
     471             : 
     472             :     // Test positive slope bresenham diagnoals across the whole raster.
     473             :     // Both high above terrain.
     474           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 120, 460, 120, 0, 460,
     475             :                                          nullptr, nullptr, nullptr));
     476             :     // Both heights are 1m above in the corners, but middle terrain violates LOS.
     477           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 120, 203, 120, 0, 247,
     478             :                                           nullptr, nullptr, nullptr));
     479           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 120, 203, 120, 0, 247,
     480             :                                           pXIntersection, pYIntersection,
     481             :                                           nullptr));
     482             : 
     483           1 :     EXPECT_EQ(*pXIntersection, 120);
     484           1 :     EXPECT_EQ(*pYIntersection, 0);
     485             : 
     486             :     // Vertical line tests with hill between two points, in both directions.
     487           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 83, 111, 154, 83, 117, 198,
     488             :                                           nullptr, nullptr, nullptr));
     489           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 83, 117, 198, 83, 111, 154,
     490             :                                           nullptr, nullptr, nullptr));
     491           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 83, 111, 460, 83, 117, 460,
     492             :                                          nullptr, nullptr, nullptr));
     493           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 83, 117, 460, 83, 111, 460,
     494             :                                          nullptr, nullptr, nullptr));
     495             : 
     496             :     // Horizontal line tests with hill between two points, in both directions.
     497           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 75, 115, 192, 89, 115, 191,
     498             :                                           nullptr, nullptr, nullptr));
     499           1 :     EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 89, 115, 191, 75, 115, 192,
     500             :                                           nullptr, nullptr, nullptr));
     501           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 75, 115, 460, 89, 115, 460,
     502             :                                          nullptr, nullptr, nullptr));
     503           1 :     EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 89, 115, 460, 75, 115, 460,
     504             :                                          nullptr, nullptr, nullptr));
     505             : }
     506             : 
     507             : }  // namespace

Generated by: LCOV version 1.14