Skip to content

Commit

Permalink
Merge pull request #1658 from rouault/map_OSRSetPROJSearchPaths_to_SWIG
Browse files Browse the repository at this point in the history
SWIG: add osr.SetPROJSearchPath(path) that can be used since setting PROJ_LIB from C# does no work (fixes #1647)
  • Loading branch information
rouault committed Jun 19, 2019
2 parents dabadf7 + 94a03d0 commit ec53c1f
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 1 deletion.
38 changes: 37 additions & 1 deletion autotest/osr/osr_basic.py
Expand Up @@ -36,7 +36,7 @@
import gdaltest
from osgeo import osr
import pytest

from threading import Thread

###############################################################################
# Create a UTM WGS84 coordinate system and check various items.
Expand Down Expand Up @@ -1533,3 +1533,39 @@ def test_osr_get_name():
assert sr.GetName() is None
sr.SetWellKnownGeogCS('WGS84')
assert sr.GetName() == 'WGS 84'


def test_SetPROJSearchPath():

# OSRSetPROJSearchPaths() is only taken into priority over other methods
# starting with PROJ >= 6.1
if not(osr.GetPROJVersionMajor() > 6 or osr.GetPROJVersionMinor() >= 1):
pytest.skip()

# Do the test in a new thread, so that SetPROJSearchPath() is taken
# into account
def threaded_function(arg):
sr = osr.SpatialReference()
with gdaltest.error_handler():
arg[0] = sr.ImportFromEPSG(32631)

try:
arg = [ -1 ]

thread = Thread(target = threaded_function, args = (arg, ))
thread.start()
thread.join()
assert arg[0] == 0

osr.SetPROJSearchPath('/i_do/not/exist')

thread = Thread(target = threaded_function, args = (arg, ))
thread.start()
thread.join()
assert arg[0] > 0
finally:
# Cancel search path (we can't call SetPROJSearchPath(None))
osr.SetPROJSearchPaths([])

sr = osr.SpatialReference()
assert sr.ImportFromEPSG(32631) == 0
22 changes: 22 additions & 0 deletions gdal/ogr/ogr_proj_p.cpp
Expand Up @@ -149,3 +149,25 @@ void OSRSetPROJSearchPaths( const char* const * papszPaths )
g_searchPathGenerationCounter ++;
g_aosSearchpaths.Assign(CSLDuplicate(papszPaths), true);
}

/************************************************************************/
/* OSRGetPROJVersion() */
/************************************************************************/

/** \brief Get the PROJ version
*
* @param pnMajor Pointer to major version number, or NULL
* @param pnMinor Pointer to minor version number, or NULL
* @param pnPatch Pointer to patch version number, or NULL
* @since GDAL 3.0.1
*/
void OSRGetPROJVersion( int* pnMajor, int* pnMinor, int* pnPatch )
{
auto info = proj_info();
if (pnMajor)
*pnMajor = info.major;
if (pnMinor)
*pnMinor = info.minor;
if (pnPatch)
*pnPatch = info.patch;
}
1 change: 1 addition & 0 deletions gdal/ogr/ogr_srs_api.h
Expand Up @@ -464,6 +464,7 @@ typedef void *OGRCoordinateTransformationH;
#endif

void CPL_DLL OSRSetPROJSearchPaths( const char* const * papszPaths );
void CPL_DLL OSRGetPROJVersion( int* pnMajor, int* pnMinor, int* pnPatch );

OGRSpatialReferenceH CPL_DLL CPL_STDCALL
OSRNewSpatialReference( const char * /* = NULL */);
Expand Down
32 changes: 32 additions & 0 deletions gdal/swig/include/osr.i
Expand Up @@ -1373,6 +1373,38 @@ void GetCRSInfoListFromDatabase( const char *authName,

#endif // SWIGPYTHON

%inline %{
void SetPROJSearchPath( const char *utf8_path )
{
const char* const apszPaths[2] = { utf8_path, NULL };
OSRSetPROJSearchPaths(apszPaths);
}
%}

%apply (char **options) { (char **) };
%inline %{
void SetPROJSearchPaths( char** paths )
{
OSRSetPROJSearchPaths(paths);
}
%}
%clear (char **);

%inline %{
int GetPROJVersionMajor()
{
int num;
OSRGetPROJVersion(&num, NULL, NULL);
return num;
}

int GetPROJVersionMinor()
{
int num;
OSRGetPROJVersion(NULL, &num, NULL);
return num;
}
%}

#ifdef SWIGPYTHON
%thread;
Expand Down
222 changes: 222 additions & 0 deletions gdal/swig/python/extensions/osr_wrap.cpp
Expand Up @@ -4495,6 +4495,34 @@ void GetCRSInfoListFromDatabase( const char *authName,
*pList = OSRGetCRSInfoListFromDatabase(authName, NULL, pnListCount);
}


void SetPROJSearchPath( const char *utf8_path )
{
const char* const apszPaths[2] = { utf8_path, NULL };
OSRSetPROJSearchPaths(apszPaths);
}


void SetPROJSearchPaths( char** paths )
{
OSRSetPROJSearchPaths(paths);
}


int GetPROJVersionMajor()
{
int num;
OSRGetPROJVersion(&num, NULL, NULL);
return num;
}

int GetPROJVersionMinor()
{
int num;
OSRGetPROJVersion(NULL, &num, NULL);
return num;
}

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -18920,6 +18948,196 @@ SWIGINTERN PyObject *_wrap_GetCRSInfoListFromDatabase(PyObject *SWIGUNUSEDPARM(s
}


SWIGINTERN PyObject *_wrap_SetPROJSearchPath(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0; int bLocalUseExceptionsCode = bUseExceptions;
char *arg1 = (char *) 0 ;
int bToFree1 = 0 ;
PyObject * obj0 = 0 ;

if (!PyArg_ParseTuple(args,(char *)"O:SetPROJSearchPath",&obj0)) SWIG_fail;
{
/* %typemap(in) (const char *utf8_path) */
arg1 = GDALPythonObjectToCStr( obj0, &bToFree1 );
if (arg1 == NULL)
{
PyErr_SetString( PyExc_RuntimeError, "not a string" );
SWIG_fail;
}
}
{
if ( bUseExceptions ) {
ClearErrorState();
}
SetPROJSearchPath((char const *)arg1);
#ifndef SED_HACKS
if ( bUseExceptions ) {
CPLErr eclass = CPLGetLastErrorType();
if ( eclass == CE_Failure || eclass == CE_Fatal ) {
SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
}
}
#endif
}
resultobj = SWIG_Py_Void();
{
/* %typemap(freearg) (const char *utf8_path) */
GDALPythonFreeCStr(arg1, bToFree1);
}
if ( ReturnSame(bLocalUseExceptionsCode) ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { Py_XDECREF(resultobj); SWIG_Error( SWIG_RuntimeError, CPLGetLastErrorMsg() ); return NULL; } }
return resultobj;
fail:
{
/* %typemap(freearg) (const char *utf8_path) */
GDALPythonFreeCStr(arg1, bToFree1);
}
return NULL;
}


SWIGINTERN PyObject *_wrap_SetPROJSearchPaths(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0; int bLocalUseExceptionsCode = bUseExceptions;
char **arg1 = (char **) 0 ;
PyObject * obj0 = 0 ;

if (!PyArg_ParseTuple(args,(char *)"O:SetPROJSearchPaths",&obj0)) SWIG_fail;
{
/* %typemap(in) char **options */
/* Check if is a list (and reject strings, that are seen as sequence of characters) */
if ( ! PySequence_Check(obj0) || PyUnicode_Check(obj0)
#if PY_VERSION_HEX < 0x03000000
|| PyString_Check(obj0)
#endif
) {
PyErr_SetString(PyExc_TypeError,"not a sequence");
SWIG_fail;
}

Py_ssize_t size = PySequence_Size(obj0);
if( size != (int)size ) {
PyErr_SetString(PyExc_TypeError, "too big sequence");
SWIG_fail;
}
for (int i = 0; i < (int)size; i++) {
PyObject* pyObj = PySequence_GetItem(obj0,i);
if (PyUnicode_Check(pyObj))
{
char *pszStr;
Py_ssize_t nLen;
PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
if( !pyUTF8Str )
{
Py_DECREF(pyObj);
PyErr_SetString(PyExc_TypeError,"invalid Unicode sequence");
SWIG_fail;
}
#if PY_VERSION_HEX >= 0x03000000
PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
#else
PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
#endif
arg1 = CSLAddString( arg1, pszStr );
Py_XDECREF(pyUTF8Str);
}
#if PY_VERSION_HEX >= 0x03000000
else if (PyBytes_Check(pyObj))
arg1 = CSLAddString( arg1, PyBytes_AsString(pyObj) );
#else
else if (PyString_Check(pyObj))
arg1 = CSLAddString( arg1, PyString_AsString(pyObj) );
#endif
else
{
Py_DECREF(pyObj);
PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
SWIG_fail;
}
Py_DECREF(pyObj);
}
}
{
if ( bUseExceptions ) {
ClearErrorState();
}
SetPROJSearchPaths(arg1);
#ifndef SED_HACKS
if ( bUseExceptions ) {
CPLErr eclass = CPLGetLastErrorType();
if ( eclass == CE_Failure || eclass == CE_Fatal ) {
SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
}
}
#endif
}
resultobj = SWIG_Py_Void();
{
/* %typemap(freearg) char **options */
CSLDestroy( arg1 );
}
if ( ReturnSame(bLocalUseExceptionsCode) ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { Py_XDECREF(resultobj); SWIG_Error( SWIG_RuntimeError, CPLGetLastErrorMsg() ); return NULL; } }
return resultobj;
fail:
{
/* %typemap(freearg) char **options */
CSLDestroy( arg1 );
}
return NULL;
}


SWIGINTERN PyObject *_wrap_GetPROJVersionMajor(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0; int bLocalUseExceptionsCode = bUseExceptions;
int result;

if (!PyArg_ParseTuple(args,(char *)":GetPROJVersionMajor")) SWIG_fail;
{
if ( bUseExceptions ) {
ClearErrorState();
}
result = (int)GetPROJVersionMajor();
#ifndef SED_HACKS
if ( bUseExceptions ) {
CPLErr eclass = CPLGetLastErrorType();
if ( eclass == CE_Failure || eclass == CE_Fatal ) {
SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
}
}
#endif
}
resultobj = SWIG_From_int(static_cast< int >(result));
if ( ReturnSame(bLocalUseExceptionsCode) ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { Py_XDECREF(resultobj); SWIG_Error( SWIG_RuntimeError, CPLGetLastErrorMsg() ); return NULL; } }
return resultobj;
fail:
return NULL;
}


SWIGINTERN PyObject *_wrap_GetPROJVersionMinor(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0; int bLocalUseExceptionsCode = bUseExceptions;
int result;

if (!PyArg_ParseTuple(args,(char *)":GetPROJVersionMinor")) SWIG_fail;
{
if ( bUseExceptions ) {
ClearErrorState();
}
result = (int)GetPROJVersionMinor();
#ifndef SED_HACKS
if ( bUseExceptions ) {
CPLErr eclass = CPLGetLastErrorType();
if ( eclass == CE_Failure || eclass == CE_Fatal ) {
SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
}
}
#endif
}
resultobj = SWIG_From_int(static_cast< int >(result));
if ( ReturnSame(bLocalUseExceptionsCode) ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { Py_XDECREF(resultobj); SWIG_Error( SWIG_RuntimeError, CPLGetLastErrorMsg() ); return NULL; } }
return resultobj;
fail:
return NULL;
}


static PyMethodDef SwigMethods[] = {
{ (char *)"SWIG_PyInstanceMethod_New", (PyCFunction)SWIG_PyInstanceMethod_New, METH_O, NULL},
{ (char *)"SRS_WKT_WGS84_LAT_LONG_swigconstant", SRS_WKT_WGS84_LAT_LONG_swigconstant, METH_VARARGS, NULL},
Expand Down Expand Up @@ -19296,6 +19514,10 @@ static PyMethodDef SwigMethods[] = {
{ (char *)"OSRCRSInfo_area_name_get", _wrap_OSRCRSInfo_area_name_get, METH_VARARGS, (char *)"OSRCRSInfo_area_name_get(CRSInfo crsInfo) -> char const *"},
{ (char *)"OSRCRSInfo_projection_method_get", _wrap_OSRCRSInfo_projection_method_get, METH_VARARGS, (char *)"OSRCRSInfo_projection_method_get(CRSInfo crsInfo) -> char const *"},
{ (char *)"GetCRSInfoListFromDatabase", _wrap_GetCRSInfoListFromDatabase, METH_VARARGS, (char *)"GetCRSInfoListFromDatabase(char const * authName)"},
{ (char *)"SetPROJSearchPath", _wrap_SetPROJSearchPath, METH_VARARGS, (char *)"SetPROJSearchPath(char const * utf8_path)"},
{ (char *)"SetPROJSearchPaths", _wrap_SetPROJSearchPaths, METH_VARARGS, (char *)"SetPROJSearchPaths(char ** paths)"},
{ (char *)"GetPROJVersionMajor", _wrap_GetPROJVersionMajor, METH_VARARGS, (char *)"GetPROJVersionMajor() -> int"},
{ (char *)"GetPROJVersionMinor", _wrap_GetPROJVersionMinor, METH_VARARGS, (char *)"GetPROJVersionMinor() -> int"},
{ NULL, NULL, 0, NULL }
};

Expand Down
16 changes: 16 additions & 0 deletions gdal/swig/python/osgeo/osr.py
Expand Up @@ -1534,6 +1534,22 @@ def OSRCRSInfo_projection_method_get(*args):
def GetCRSInfoListFromDatabase(*args):
"""GetCRSInfoListFromDatabase(char const * authName)"""
return _osr.GetCRSInfoListFromDatabase(*args)

def SetPROJSearchPath(*args):
"""SetPROJSearchPath(char const * utf8_path)"""
return _osr.SetPROJSearchPath(*args)

def SetPROJSearchPaths(*args):
"""SetPROJSearchPaths(char ** paths)"""
return _osr.SetPROJSearchPaths(*args)

def GetPROJVersionMajor(*args):
"""GetPROJVersionMajor() -> int"""
return _osr.GetPROJVersionMajor(*args)

def GetPROJVersionMinor(*args):
"""GetPROJVersionMinor() -> int"""
return _osr.GetPROJVersionMinor(*args)
# This file is compatible with both classic and new-style classes.


0 comments on commit ec53c1f

Please sign in to comment.