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 1 : const auto lambda = [](GDALDataset *poDS)
141 : {
142 : std::unique_ptr<GDALWarpOptions, decltype(&GDALDestroyWarpOptions)>
143 2 : psOptions(GDALCreateWarpOptions(), GDALDestroyWarpOptions);
144 1 : psOptions->hSrcDS = GDALDataset::ToHandle(poDS);
145 1 : psOptions->nBandCount = 1;
146 2 : psOptions->panSrcBands =
147 1 : static_cast<int *>(CPLMalloc(psOptions->nBandCount * sizeof(int)));
148 1 : psOptions->panSrcBands[0] = 1;
149 2 : psOptions->padfSrcNoDataReal =
150 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
151 1 : psOptions->padfSrcNoDataReal[0] = 0.0;
152 1 : GDALWarpResolveWorkingDataType(psOptions.get());
153 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
154 :
155 1 : psOptions->padfSrcNoDataReal[0] = -1.0;
156 1 : GDALWarpResolveWorkingDataType(psOptions.get());
157 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
158 :
159 1 : psOptions->eWorkingDataType = GDT_Unknown;
160 1 : psOptions->padfSrcNoDataReal[0] = 2.0;
161 1 : GDALWarpResolveWorkingDataType(psOptions.get());
162 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
163 1 : };
164 :
165 : GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
166 2 : ->Create("", 1, 1, 1, GDT_Byte, nullptr));
167 1 : lambda(poDS.get());
168 1 : }
169 :
170 : // GDALWarpResolveWorkingDataType: effect of padfSrcNoDataImag
171 4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfSrcNoDataImag)
172 : {
173 1 : GDALWarpOptions *psOptions = GDALCreateWarpOptions();
174 1 : psOptions->nBandCount = 1;
175 1 : psOptions->padfSrcNoDataReal =
176 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
177 1 : psOptions->padfSrcNoDataImag =
178 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
179 1 : psOptions->padfSrcNoDataReal[0] = 0.0;
180 1 : psOptions->padfSrcNoDataImag[0] = 0.0;
181 1 : GDALWarpResolveWorkingDataType(psOptions);
182 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
183 :
184 1 : psOptions->eWorkingDataType = GDT_Unknown;
185 1 : psOptions->padfSrcNoDataReal[0] = 0.0;
186 1 : psOptions->padfSrcNoDataImag[0] = 1.0;
187 1 : GDALWarpResolveWorkingDataType(psOptions);
188 : // Could probably be CInt16
189 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CInt32);
190 :
191 1 : psOptions->eWorkingDataType = GDT_Unknown;
192 1 : psOptions->padfSrcNoDataReal[0] = 0.0;
193 1 : psOptions->padfSrcNoDataImag[0] = 1.5;
194 1 : GDALWarpResolveWorkingDataType(psOptions);
195 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat32);
196 :
197 1 : psOptions->eWorkingDataType = GDT_Unknown;
198 1 : psOptions->padfSrcNoDataReal[0] = 0.0;
199 1 : psOptions->padfSrcNoDataImag[0] = 2.12345678;
200 1 : GDALWarpResolveWorkingDataType(psOptions);
201 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat64);
202 :
203 1 : GDALDestroyWarpOptions(psOptions);
204 1 : }
205 :
206 : // GDALWarpResolveWorkingDataType: effect of padfDstNoDataReal
207 4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfDstNoDataReal)
208 : {
209 1 : GDALWarpOptions *psOptions = GDALCreateWarpOptions();
210 1 : psOptions->nBandCount = 1;
211 1 : psOptions->padfDstNoDataReal =
212 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
213 1 : psOptions->padfDstNoDataReal[0] = 0.0;
214 1 : GDALWarpResolveWorkingDataType(psOptions);
215 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
216 :
217 1 : psOptions->eWorkingDataType = GDT_Unknown;
218 1 : psOptions->padfDstNoDataReal[0] = -1.0;
219 1 : GDALWarpResolveWorkingDataType(psOptions);
220 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Int16);
221 :
222 1 : psOptions->eWorkingDataType = GDT_Unknown;
223 1 : psOptions->padfDstNoDataReal[0] = 2.0;
224 1 : GDALWarpResolveWorkingDataType(psOptions);
225 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
226 :
227 1 : psOptions->eWorkingDataType = GDT_Unknown;
228 1 : psOptions->padfDstNoDataReal[0] = 256.0;
229 1 : GDALWarpResolveWorkingDataType(psOptions);
230 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_UInt16);
231 :
232 1 : psOptions->eWorkingDataType = GDT_Unknown;
233 1 : psOptions->padfDstNoDataReal[0] = 2.5;
234 1 : GDALWarpResolveWorkingDataType(psOptions);
235 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float32);
236 :
237 1 : psOptions->eWorkingDataType = GDT_Unknown;
238 1 : psOptions->padfDstNoDataReal[0] = 2.12345678;
239 1 : GDALWarpResolveWorkingDataType(psOptions);
240 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Float64);
241 :
242 1 : GDALDestroyWarpOptions(psOptions);
243 1 : }
244 :
245 : // GDALWarpResolveWorkingDataType: effect of padfDstNoDataImag
246 4 : TEST_F(test_alg, GDALWarpResolveWorkingDataType_padfDstNoDataImag)
247 : {
248 1 : GDALWarpOptions *psOptions = GDALCreateWarpOptions();
249 1 : psOptions->nBandCount = 1;
250 1 : psOptions->padfDstNoDataReal =
251 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
252 1 : psOptions->padfDstNoDataImag =
253 1 : static_cast<double *>(CPLMalloc(sizeof(double)));
254 1 : psOptions->padfDstNoDataReal[0] = 0.0;
255 1 : psOptions->padfDstNoDataImag[0] = 0.0;
256 1 : GDALWarpResolveWorkingDataType(psOptions);
257 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_Byte);
258 :
259 1 : psOptions->eWorkingDataType = GDT_Unknown;
260 1 : psOptions->padfDstNoDataReal[0] = 0.0;
261 1 : psOptions->padfDstNoDataImag[0] = 1.0;
262 1 : GDALWarpResolveWorkingDataType(psOptions);
263 : // Could probably be CInt16
264 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CInt32);
265 :
266 1 : psOptions->eWorkingDataType = GDT_Unknown;
267 1 : psOptions->padfDstNoDataImag[0] = 0.0;
268 1 : psOptions->padfDstNoDataImag[0] = 1.5;
269 1 : GDALWarpResolveWorkingDataType(psOptions);
270 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat32);
271 :
272 1 : psOptions->eWorkingDataType = GDT_Unknown;
273 1 : psOptions->padfDstNoDataImag[0] = 0.0;
274 1 : psOptions->padfDstNoDataImag[0] = 2.12345678;
275 1 : GDALWarpResolveWorkingDataType(psOptions);
276 1 : EXPECT_EQ(psOptions->eWorkingDataType, GDT_CFloat64);
277 :
278 1 : GDALDestroyWarpOptions(psOptions);
279 1 : }
280 :
281 : // Test GDALAutoCreateWarpedVRT() with creation of an alpha band
282 4 : TEST_F(test_alg, GDALAutoCreateWarpedVRT_alpha_band)
283 : {
284 : GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
285 1 : ->Create("", 1, 1, 1, GDT_Byte, nullptr));
286 1 : poDS->SetProjection(SRS_WKT_WGS84_LAT_LONG);
287 1 : double adfGeoTransform[6] = {10, 1, 0, 20, 0, -1};
288 1 : poDS->SetGeoTransform(adfGeoTransform);
289 1 : GDALWarpOptions *psOptions = GDALCreateWarpOptions();
290 1 : psOptions->nDstAlphaBand = 2;
291 : GDALDatasetH hWarpedVRT =
292 1 : GDALAutoCreateWarpedVRT(GDALDataset::ToHandle(poDS.get()), nullptr,
293 : nullptr, GRA_NearestNeighbour, 0.0, psOptions);
294 1 : ASSERT_TRUE(hWarpedVRT != nullptr);
295 1 : ASSERT_EQ(GDALGetRasterCount(hWarpedVRT), 2);
296 1 : EXPECT_EQ(
297 : GDALGetRasterColorInterpretation(GDALGetRasterBand(hWarpedVRT, 2)),
298 : GCI_AlphaBand);
299 1 : GDALDestroyWarpOptions(psOptions);
300 1 : GDALClose(hWarpedVRT);
301 : }
302 :
303 : // Test GDALIsLineOfSightVisible() with single point dataset
304 4 : TEST_F(test_alg, GDALIsLineOfSightVisible_single_point_dataset)
305 : {
306 1 : auto const sizeX = 1;
307 1 : auto const sizeY = 1;
308 1 : auto const numBands = 1;
309 : GDALDatasetUniquePtr poDS(
310 : GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
311 1 : ->Create("", sizeX, sizeY, numBands, GDT_Int8, nullptr));
312 1 : ASSERT_TRUE(poDS != nullptr);
313 :
314 1 : int8_t val = 42;
315 1 : auto pBand = poDS->GetRasterBand(1);
316 1 : ASSERT_TRUE(pBand != nullptr);
317 1 : ASSERT_TRUE(poDS->RasterIO(GF_Write, 0, 0, 1, 1, &val, 1, 1, GDT_Int8, 1,
318 : nullptr, 0, 0, 0, nullptr) == CE_None);
319 : // Both points below terrain
320 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 0.0, 0, 0, 0.0, nullptr,
321 : nullptr, nullptr));
322 : // One point below terrain
323 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 0.0, 0, 0, 43.0, nullptr,
324 : nullptr, nullptr));
325 : int xIntersection, yIntersection;
326 1 : int *pXIntersection = &xIntersection;
327 1 : int *pYIntersection = &yIntersection;
328 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(
329 : pBand, 0, 0, 0.0, 0, 0, 43.0, pXIntersection, pYIntersection, nullptr));
330 1 : EXPECT_EQ(*pXIntersection, 0);
331 1 : EXPECT_EQ(*pYIntersection, 0);
332 : // Both points above terrain
333 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 44.0, 0, 0, 43.0, nullptr,
334 : nullptr, nullptr));
335 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 44.0, 0, 0, 43.0,
336 : pXIntersection, pYIntersection,
337 : nullptr));
338 : }
339 :
340 : // Test GDALIsLineOfSightVisible() with 10x10 default dataset
341 4 : TEST_F(test_alg, GDALIsLineOfSightVisible_default_square_dataset)
342 : {
343 1 : auto const sizeX = 10;
344 1 : auto const sizeY = 10;
345 1 : auto const numBands = 1;
346 : GDALDatasetUniquePtr poDS(
347 : GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
348 1 : ->Create("", sizeX, sizeY, numBands, GDT_Int8, nullptr));
349 1 : ASSERT_TRUE(poDS != nullptr);
350 :
351 1 : auto pBand = poDS->GetRasterBand(1);
352 1 : ASSERT_TRUE(pBand != nullptr);
353 :
354 1 : const int x1 = 1;
355 1 : const int y1 = 1;
356 1 : const int x2 = 2;
357 1 : const int y2 = 2;
358 :
359 : // Both points are above terrain.
360 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x1, y1, 1.0, x2, y2, 1.0,
361 : nullptr, nullptr, nullptr));
362 : // Both points are above terrain, supply intersection.
363 : int xIntersection, yIntersection;
364 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x1, y1, 1.0, x2, y2, 1.0,
365 : &xIntersection, &yIntersection,
366 : nullptr));
367 : // Flip the order, same result.
368 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, x2, y2, 1.0, x1, y1, 1.0,
369 : nullptr, nullptr, nullptr));
370 :
371 : // One point is below terrain.
372 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, 1.0,
373 : nullptr, nullptr, nullptr));
374 1 : int *pXIntersection = &xIntersection;
375 1 : int *pYIntersection = &yIntersection;
376 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, 1.0,
377 : pXIntersection, pYIntersection,
378 : nullptr));
379 1 : EXPECT_EQ(*pXIntersection, 1);
380 1 : EXPECT_EQ(*pYIntersection, 1);
381 : // Flip the order, same result.
382 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x2, y2, -1.0, x1, y1, 1.0,
383 : pXIntersection, pYIntersection,
384 : nullptr));
385 1 : EXPECT_EQ(*pXIntersection, 2);
386 1 : EXPECT_EQ(*pYIntersection, 2);
387 :
388 : // Both points are below terrain.
389 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x1, y1, -1.0, x2, y2, -1.0,
390 : nullptr, nullptr, nullptr));
391 : // Flip the order, same result.
392 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, x2, y2, -1.0, x1, y1, -1.0,
393 : nullptr, nullptr, nullptr));
394 : }
395 :
396 : // Test GDALIsLineOfSightVisible() through a mountain (not a unit test)
397 4 : TEST_F(test_alg, GDALIsLineOfSightVisible_through_mountain)
398 : {
399 1 : GDALAllRegister();
400 :
401 1 : const std::string path = data_ + SEP + "n43.dt0";
402 : const auto poDS = GDALDatasetUniquePtr(
403 1 : GDALDataset::FromHandle(GDALOpen(path.c_str(), GA_ReadOnly)));
404 1 : if (!poDS)
405 : {
406 0 : GTEST_SKIP() << "Cannot open " << path;
407 : }
408 :
409 1 : auto pBand = poDS->GetRasterBand(1);
410 1 : ASSERT_TRUE(pBand != nullptr);
411 : std::array<double, 6> geoFwdTransform;
412 1 : ASSERT_TRUE(poDS->GetGeoTransform(geoFwdTransform.data()) == CE_None);
413 : std::array<double, 6> geoInvTransform;
414 1 : ASSERT_TRUE(
415 : GDALInvGeoTransform(geoFwdTransform.data(), geoInvTransform.data()));
416 :
417 : // Check both sides of a mesa (north and south ends).
418 : // Top mesa at (x=8,y=58,alt=221)
419 1 : const double mesaLatTop = 43.5159;
420 1 : const double mesaLngTop = -79.9327;
421 :
422 : // Bottom is at (x=12,y=64,alt=199)
423 1 : const double mesaLatBottom = 43.4645;
424 1 : const double mesaLngBottom = -79.8985;
425 :
426 : // In between the two locations, the mesa reaches a local max altiude of 321.
427 :
428 : double dMesaTopX, dMesaTopY, dMesaBottomX, dMesaBottomY;
429 1 : GDALApplyGeoTransform(geoInvTransform.data(), mesaLngTop, mesaLatTop,
430 : &dMesaTopX, &dMesaTopY);
431 1 : GDALApplyGeoTransform(geoInvTransform.data(), mesaLngBottom, mesaLatBottom,
432 : &dMesaBottomX, &dMesaBottomY);
433 1 : const int iMesaTopX = static_cast<int>(dMesaTopX);
434 1 : const int iMesaTopY = static_cast<int>(dMesaTopY);
435 1 : const int iMesaBottomX = static_cast<int>(dMesaBottomX);
436 1 : const int iMesaBottomY = static_cast<int>(dMesaBottomY);
437 :
438 : // Both points are just above terrain, with terrain between.
439 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 222,
440 : iMesaBottomX, iMesaBottomY, 199,
441 : nullptr, nullptr, nullptr));
442 : // Flip the order, same result.
443 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaBottomX, iMesaBottomY,
444 : 199, iMesaTopX, iMesaTopY, 222,
445 : nullptr, nullptr, nullptr));
446 :
447 : // Both points above terrain.
448 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 322,
449 : iMesaBottomX, iMesaBottomY, 322,
450 : nullptr, nullptr, nullptr));
451 :
452 : // Both points below terrain.
453 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, iMesaTopX, iMesaTopY, 0,
454 : iMesaBottomX, iMesaBottomY, 0,
455 : nullptr, nullptr, nullptr));
456 :
457 : // Test negative slope bresenham diagonals across the whole raster.
458 : // Both high above terrain.
459 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 0, 460, 120, 120, 460,
460 : nullptr, nullptr, nullptr));
461 : // Both heights are 1m above in the corners, but middle terrain violates LOS.
462 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 295, 120, 120, 183,
463 : nullptr, nullptr, nullptr));
464 :
465 : int xIntersection, yIntersection;
466 1 : int *pXIntersection = &xIntersection;
467 1 : int *pYIntersection = &yIntersection;
468 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 0, 295, 120, 120, 183,
469 : pXIntersection, pYIntersection,
470 : nullptr));
471 1 : EXPECT_EQ(*pXIntersection, 2);
472 1 : EXPECT_EQ(*pYIntersection, 2);
473 :
474 : // Test positive slope bresenham diagnoals across the whole raster.
475 : // Both high above terrain.
476 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 0, 120, 460, 120, 0, 460,
477 : nullptr, nullptr, nullptr));
478 : // Both heights are 1m above in the corners, but middle terrain violates LOS.
479 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 120, 203, 120, 0, 247,
480 : nullptr, nullptr, nullptr));
481 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 0, 120, 203, 120, 0, 247,
482 : pXIntersection, pYIntersection,
483 : nullptr));
484 :
485 1 : EXPECT_EQ(*pXIntersection, 120);
486 1 : EXPECT_EQ(*pYIntersection, 0);
487 :
488 : // Vertical line tests with hill between two points, in both directions.
489 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 83, 111, 154, 83, 117, 198,
490 : nullptr, nullptr, nullptr));
491 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 83, 117, 198, 83, 111, 154,
492 : nullptr, nullptr, nullptr));
493 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 83, 111, 460, 83, 117, 460,
494 : nullptr, nullptr, nullptr));
495 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 83, 117, 460, 83, 111, 460,
496 : nullptr, nullptr, nullptr));
497 :
498 : // Horizontal line tests with hill between two points, in both directions.
499 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 75, 115, 192, 89, 115, 191,
500 : nullptr, nullptr, nullptr));
501 1 : EXPECT_FALSE(GDALIsLineOfSightVisible(pBand, 89, 115, 191, 75, 115, 192,
502 : nullptr, nullptr, nullptr));
503 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 75, 115, 460, 89, 115, 460,
504 : nullptr, nullptr, nullptr));
505 1 : EXPECT_TRUE(GDALIsLineOfSightVisible(pBand, 89, 115, 460, 75, 115, 460,
506 : nullptr, nullptr, nullptr));
507 : }
508 :
509 : } // namespace
|