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: 2024-11-21 22:18:42 Functions: 49 50 98.0 %

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

Generated by: LCOV version 1.14