diff --git a/alg/gdal_alg.h b/alg/gdal_alg.h index 8d2206b04751..9b1daf10c683 100644 --- a/alg/gdal_alg.h +++ b/alg/gdal_alg.h @@ -359,8 +359,8 @@ GDALDatasetH CPL_DLL GDALViewshedGenerate( bool CPL_DLL GDALIsLineOfSightVisible( const GDALRasterBandH, const int xA, const int yA, const double zA, - const int xB, const int yB, const double zB, int *xTerrainIntersection, - int *yTerrainIntersection, CSLConstList papszOptions); + const int xB, const int yB, const double zB, int *pnxTerrainIntersection, + int *pnyTerrainIntersection, CSLConstList papszOptions); /************************************************************************/ /* Rasterizer API - geometries burned into GDAL raster. */ diff --git a/alg/los.cpp b/alg/los.cpp index ad55749e14d9..e1b420ceb689 100644 --- a/alg/los.cpp +++ b/alg/los.cpp @@ -162,27 +162,31 @@ static bool IsAboveTerrain(const GDALRasterBandH hBand, const int x, * For example, datasets referenced against geographic coordinate at high latitudes may have issues. * * @param hBand The band to read the DEM data from. This must NOT be null. - * + * * @param xA The X location (raster column) of the first point to check on the raster. * * @param yA The Y location (raster row) of the first point to check on the raster. - * + * * @param zA The Z location (height) of the first point to check. - * + * * @param xB The X location (raster column) of the second point to check on the raster. * * @param yB The Y location (raster row) of the second point to check on the raster. - * + * * @param zB The Z location (height) of the second point to check. - * - * @param xTerrainIntersection The X location where the LOS line intersects with terrain, - * or nullptr if it does not intersect terrain. Currently ignored. - * - * @param yTerrainIntersection The Y location where the LOS line intersects with terrain, - * or nullptr if it does not intersect terrain. Currently ignored. - * + * + * @param[out] pnxTerrainIntersection The X location where the LOS line + * intersects with terrain, or nullptr if it does not intersect + * terrain. Not implemented currently (*pnxTerrainIntersection + * is set to -1) + * + * @param[out] pnyTerrainIntersection The Y location where the LOS line + * intersects with terrain, or nullptr if it does not intersect + * terrain. Not implemented currently (*pnyTerrainIntersection + * is set to -1) + * * @param papszOptions Options for the line of sight algorithm (currently ignored). - * + * * @return True if the two points are within Line of Sight. * * @since GDAL 3.9 @@ -191,12 +195,18 @@ static bool IsAboveTerrain(const GDALRasterBandH hBand, const int x, bool GDALIsLineOfSightVisible(const GDALRasterBandH hBand, const int xA, const int yA, const double zA, const int xB, const int yB, const double zB, - CPL_UNUSED int *xTerrainIntersection, - CPL_UNUSED int *yTerrainIntersection, + int *pnxTerrainIntersection, + int *pnyTerrainIntersection, CPL_UNUSED CSLConstList papszOptions) { VALIDATE_POINTER1(hBand, "GDALIsLineOfSightVisible", false); + if (pnxTerrainIntersection) + *pnxTerrainIntersection = -1; + + if (pnyTerrainIntersection) + *pnyTerrainIntersection = -1; + // Perform a preliminary check of the start and end points. if (!IsAboveTerrain(hBand, xA, yA, zA)) { diff --git a/autotest/alg/los.py b/autotest/alg/los.py index a202a79be4e4..b38fbdbc6547 100644 --- a/autotest/alg/los.py +++ b/autotest/alg/los.py @@ -37,10 +37,14 @@ def test_los_basic(): mem_ds = gdal.GetDriverByName("MEM").Create("", 2, 1) - assert gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 1, 0, 1) - assert gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 0, 0, 1) - assert not gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, -1, 1, 0, 1) - assert not gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 1, 0, -1) + success, x, y = gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 1, 0, 1) + assert success + assert x == -1 + assert y == -1 + + assert gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 0, 0, 1)[0] + assert not gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, -1, 1, 0, 1)[0] + assert not gdal.IsLineOfSightVisible(mem_ds.GetRasterBand(1), 0, 0, 1, 1, 0, -1)[0] with pytest.raises(Exception, match="Received a NULL pointer"): assert gdal.IsLineOfSightVisible(None, 0, 0, 0, 0, 0, 0) diff --git a/swig/include/Operations.i b/swig/include/Operations.i index 574b47b17160..7cf87b4aa446 100644 --- a/swig/include/Operations.i +++ b/swig/include/Operations.i @@ -639,6 +639,21 @@ GDALDatasetShadow *ViewshedGenerate( GDALRasterBandShadow *srcBand, /* IsLineOfSightVisible() */ /************************************************************************/ +#ifdef SWIGPYTHON +%feature( "kwargs" ) IsLineOfSightVisible; +%apply Pointer NONNULL {GDALRasterBandShadow *band}; +%inline %{ +void IsLineOfSightVisible(GDALRasterBandShadow *band, + int xA, int yA, double zA, + int xB, int yB, double zB, + bool *pbVisible, int *pnXIntersection, int *pnYIntersection, + char** options = NULL) +{ + *pbVisible = GDALIsLineOfSightVisible(band, xA, yA, zA, xB, yB, zB, pnXIntersection, pnYIntersection, options); +} +%} +%clear GDALRasterBandShadow *band; +#else #ifndef SWIGJAVA %feature( "kwargs" ) IsLineOfSightVisible; #endif @@ -647,13 +662,13 @@ GDALDatasetShadow *ViewshedGenerate( GDALRasterBandShadow *srcBand, bool IsLineOfSightVisible(GDALRasterBandShadow *band, int xA, int yA, double zA, int xB, int yB, double zB, - int *xTerrainIntersection, int *yTerrainIntersection, char** options = NULL) { - return GDALIsLineOfSightVisible(band, xA, yA, zA, xB, yB, zB, xTerrainIntersection, yTerrainIntersection, options); + return GDALIsLineOfSightVisible(band, xA, yA, zA, xB, yB, zB, NULL, NULL, options); } %} %clear GDALRasterBandShadow *band; +#endif /************************************************************************/ /* AutoCreateWarpedVRT() */ diff --git a/swig/include/python/docs/gdal_operations_docs.i b/swig/include/python/docs/gdal_operations_docs.i index dc399e30fec4..46c1c4dc252a 100644 --- a/swig/include/python/docs/gdal_operations_docs.i +++ b/swig/include/python/docs/gdal_operations_docs.i @@ -24,17 +24,13 @@ yB : int The Y location (raster row) of the second point to check on the raster. zB : float The Z location (height) of the second point to check. -xTerrainIntersection : int - The X location where the LOS line intersects with terrain, or nullptr if it does not - intersect terrain. Currently ignored. -yTerrainIntersection : int - The Y location where the LOS line intersects with terrain, or nullptr if it does not - intersect terrain. Currently ignored. options : dict/list, optional A dict or list of name=value of options for the line of sight algorithm (currently ignored). Returns ------- -bool - True if the two points are within Line of Sight. +(bool, int, int) + First value of tuple is True if the two points are within Line of Sight. + Second value is the X location where the LOS line intersects with terrain (will be set in the future, currently set to -1). + Third value is the Y location where the LOS line intersects with terrain (will be set in the future, currently set to -1). "; diff --git a/swig/include/python/typemaps_python.i b/swig/include/python/typemaps_python.i index 099376ae2c6f..eca5782f02ab 100644 --- a/swig/include/python/typemaps_python.i +++ b/swig/include/python/typemaps_python.i @@ -3449,3 +3449,22 @@ OBJECT_LIST_INPUT(GDALMDArrayHS); /* %typemap(freearg) (int nUsages, GDALRATFieldUsage *paeUsages)*/ CPLFree( $2 ); } + + +%typemap(in,numinputs=0) (bool *pbVisible, int *pnXIntersection, int *pnYIntersection) ( bool visible = 0, int nxintersection = 0, int nyintersection = 0 ) +{ + /* %typemap(in) (bool *pbVisible, int *pnXIntersection, int *pnYIntersection) */ + $1 = &visible; + $2 = &nxintersection; + $3 = &nyintersection; +} + +%typemap(argout) (bool *pbVisible, int *pnXIntersection, int *pnYIntersection) +{ + /* %typemap(argout) (bool *pbVisible, int *pnXIntersection, int *pnYIntersection) */ + PyObject *r = PyTuple_New( 3 ); + PyTuple_SetItem( r, 0, PyBool_FromLong(*$1) ); + PyTuple_SetItem( r, 1, PyLong_FromLong(*$2) ); + PyTuple_SetItem( r, 2, PyLong_FromLong(*$3) ); + $result = t_output_helper($result,r); +}