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