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