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
|