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