102 changes: 101 additions & 1 deletion src/providers/grass/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,64 @@ SET ( FUNCTIONS
"G_add_c_raster_color_rule"
"G_add_d_raster_color_rule"
"G_add_f_raster_color_rule"
"G_add_modular_color_rule"
"G_add_raster_color_rule"
"G_adjust_Cell_head"
"G_adjust_easting"
"G_adjust_east_longitude"
"G_align_window"
"G__allocate_null_bits"
"G_allocate_cell_buf"
"G_allocate_c_raster_buf"
"G_allocate_d_raster_buf"
"G_allocate_f_raster_buf"
"G_allocate_null_buf"
"G_allocate_raster_buf"
"G__calloc"
"G_chop"
"G_chrcat"
"G_chrcpy"
"G_chrmov"
"G_colors_count"
"G_col_to_easting"
"G_convert_dirseps_to_host"
"G_create_key_value"
"G_database_projection_name"
"G_date"
"G_define_flag"
"G_define_module"
"G_define_option"
"G_define_standard_option"
"G_easting_to_col"
"G_find_key_value"
"G_find_cell_stat"
"G_fopen_new"
"G_format_easting"
"G_format_northing"
"G_format_resolution"
"G_free"
"G_free_cats"
"G_free_cell_stats"
"G_free_key_value"
"G_free_raster_cats"
"G_fseek"
"G_ftell"
"G_get_cat"
"G_get_c_raster_cat"
"G_get_d_raster_cat"
"G_get_fp_range_min_max"
"G_get_f_raster_cat"
"G_getl"
"G_getl2"
"G_get_range_min_max"
"G_get_raster_cat"
"G_get_raster_row_colors"
"G_get_set_window"
"G_gettext"
"G_get_window"
"G_incr_void_ptr"
"G_index"
"G_init_cell_stats"
"G_init_colors"
"G_init_fp_range"
"G__init_null_patterns"
Expand All @@ -93,35 +127,67 @@ SET ( FUNCTIONS
"G_is_c_null_value"
"G_is_d_null_value"
"G_is_f_null_value"
"G_lat_scan"
"G_llres_scan"
"G_lon_scan"
"G__ls"
"G_ls"
"G_ls_format"
"G__malloc"
"G_make_random_colors"
"G_northing_to_row"
"G__projection_name"
"G_percent"
"G_program_name"
"G_projection"
"G_quant_add_rule"
"G_quant_free"
"G_quant_get_limits"
"G_quant_init"
"G_putenv"
"G_raster_size"
"G_read_key_value_file"
"G__realloc"
"G_rindex"
"G_row_to_northing"
"G_scan_easting"
"G_scan_northing"
"G_set_c_null_value"
"G_set_d_null_value"
"G_set_d_raster_cat"
"G_set_color_range"
"G_setenv"
"G_set_f_null_value"
"G_set_gisrc_mode"
"G_set_key_value"
"G_set_null_value"
"G_set_raster_cat"
"G_set_raster_cats_title"
"G_set_raster_value_d"
"G_set_window"
"G_store"
"G_strcasecmp"
"G_strcat"
"G_strchg"
"G_strcpy"
"G_strdup"
"G_strend"
"G_strip"
"G_strmov"
"G_strncpy"
"G_str_replace"
"G_strstr"
"G_str_to_lower"
"G_str_to_sql"
"G_str_to_upper"
"G_suppress_masking"
"G_trim_decimal"
"G_update_fp_range"
"G_update_key_value_file"
"G_update_range"
"G_window_cols"
"G_window_rows"
"G_write_key_value_file"
"G_zero"
)

Expand All @@ -133,29 +199,47 @@ SET ( FUNCTIONS
# module of the same name, i.e. in our fake library, not in the original
# true GRASS gis lib, so we have to add all functions called in true lib
# also to mapped functions in fake lib
# Maybe that above is nonsese, but on Linux symbols are resolved when called, but on
# Windows, all symbols are resolved at beginning and thus not all missing symbols are
# always catched on Linux if testing with different data

IF(MSVC)
SET ( FUNCTIONS
${FUNCTIONS}
"G__getenv"
"G_get_gisrc_mode"
)
ENDIF(MSVC)

# List of functions which are implemented in qgsgrassgislib.cpp and
# thus we only need prototype
SET ( FUNCTION_PROTOTYPES
"G_area_of_cell_at_row"
"G_ask_cell_new"
"G_ask_cell_old"
"G_asprintf"
"G_begin_cell_area_calculations"
"G_begin_distance_calculations"
"G_begin_geodesic_distance"
"G_check_input_output_name"
"G_check_overwrite"
"G_close_cell"
"G_command_history"
"G_database_units_to_meters_factor"
"G_debug"
"G_distance"
"G_done_msg"
"G_fatal_error"
"G__file_name"
"G__file_name_misc"
"G_find_cell"
"G_find_cell2"
"G_find_file"
"G_find_file2"
"G_find_file_misc"
"G_find_file2_misc"
"G_fully_qualified_name"
"G_geodesic_distance_lon_to_lon"
"G_get_cellhd"
"G_get_c_raster_row"
"G_get_c_raster_row_nomask"
Expand All @@ -165,6 +249,7 @@ SET ( FUNCTION_PROTOTYPES
"G_get_f_raster_row_nomask"
"G_get_map_row"
"G_get_map_row_nomask"
"G_get_null_value_row"
"G_get_raster_map_type"
"G_get_raster_row"
"G_get_raster_row_nomask"
Expand All @@ -177,20 +262,26 @@ SET ( FUNCTION_PROTOTYPES
"G_message"
"G_open_cell_new"
"G_open_cell_old"
"G_open_fp_cell_new"
"G_open_raster_new"
"G_parser"
"G_put_raster_row"
"G_quantize_fp_map_range"
"G_raster_map_is_fp"
"G_read_cats"
"G_read_colors"
"G_read_fp_range"
"G_read_history"
"G_read_range"
"G_read_raster_cats"
"G_remove"
"G_set_cats_title"
"G_set_error_routine"
"G_set_geodesic_distance_lat1"
"G_set_geodesic_distance_lat2"
"G_set_quant_rules"
"G_short_history"
"G__temp_element"
"G_tempfile"
"G_vasprintf"
"G_verbose_message"
Expand All @@ -214,6 +305,12 @@ FILE(READ "${GRASS_INCLUDE_DIR}/grass/gisdefs.h" HEADER_FILE)
STRING(REGEX REPLACE "(/\\*([^*]|[\r\n]|(\\*+([^*/]|[\r\n])))*\\*+/)" "" HEADER_FILE "${HEADER_FILE}")
STRING(REGEX REPLACE "#[^\r\n]*" "" HEADER_FILE "${HEADER_FILE}")

# Add G_gettext defined in glocale.h
SET ( HEADER_FILE
${HEADER_FILE}
"char *G_gettext(const char *, const char *);"
)

SET ( PROTOTYPES "// Auto generated by cmake, do not edit\n" )
LIST ( APPEND PROTOTYPES "#define GRASS_GISDEFS_H\n" )
LIST ( APPEND PROTOTYPES "extern \"C\"\n" )
Expand Down Expand Up @@ -290,9 +387,12 @@ ELSE(MSVC)
ENDIF(MSVC)
ADD_LIBRARY( ${FAKE_LIB_GRASS_GIS} MODULE qgsgrassgislib.cpp qgsgrassgislibfunctions.cpp )

# GRASS_LIBRARY_gis is path to the GRASS library used for compilation, it is the same
# on runtime on Linux and Mac but on Windows with OSGEO4W the GRASS may be installed
# in different directory
SET_TARGET_PROPERTIES(${FAKE_LIB_GRASS_GIS} PROPERTIES
CLEAN_DIRECT_OUTPUT 1
COMPILE_FLAGS "\"-DGRASS_LIB_EXPORT=${DLLEXPORT}\" \"-DGRASS_EXPORT=${DLLIMPORT}\" -DGRASS_LIBRARY_GIS=\\\"${GRASS_LIBRARY_gis}\\\" \"-I${CMAKE_CURRENT_SOURCE_DIR}\" ")
COMPILE_FLAGS "\"-DGRASS_LIB_EXPORT=${DLLEXPORT}\" \"-DGRASS_EXPORT=${DLLIMPORT}\" -DGRASS_VERSION=\\\"${GRASS_VERSION}\\\" -DGRASS_LIBRARY_GIS=\\\"${GRASS_LIBRARY_gis}\\\" \"-I${CMAKE_CURRENT_SOURCE_DIR}\" ")

IF (NOT APPLE)
SET_TARGET_PROPERTIES(${FAKE_LIB_GRASS_GIS} PROPERTIES
Expand Down
244 changes: 240 additions & 4 deletions src/providers/grass/qgsgrassgislib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#include <qmath.h>
#include <QtGlobal>

// If qgsgrassgislibfunctions.h is included on Linux, symbols defined here
Expand All @@ -26,10 +27,12 @@
#endif
#include "qgsgrassgislib.h"

#include "qgis.h"
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsdatasourceuri.h"
#include "qgsgeometry.h"
#include "qgsrectangle.h"
#include "qgsconfig.h"

Expand Down Expand Up @@ -82,12 +85,34 @@ QgsGrassGisLib GRASS_LIB_EXPORT *QgsGrassGisLib::instance( )
QgsGrassGisLib::QgsGrassGisLib()
{
// Load original GRASS library

// GRASS_LIBRARY_GIS (cmake GRASS_LIBRARY_gis) is a path to the GRASS library
// in the time of compilation, it may be used on runtime (it is the same)
// on Linux and Mac but on Windows with OSGEO4W the GRASS may be installed
// in a different directory. qgis.env however calls GRASS etc/env.bat
// which sets GISBASE and GRASS_LIBRARY_GIS on Windows is path to .lib, e.g
// grass_gis.lib. Name of the DLL on Windows is e.g.: libgrass_gis6.4.3RC1.dll

QString gisBase = getenv( "GISBASE" );
#ifdef Q_OS_WIN
if ( gisBase.isEmpty() )
{
fatal( "GISBASE environment variable not set" );
}
QString libPath = gisBase + "/lib/libgrass_gis" + QString( GRASS_VERSION ) + ".dll";
#else
QString libPath = QString( GRASS_LIBRARY_GIS );
// Prefere GISBASE if set
if ( !gisBase.isEmpty() )
{
libPath = gisBase + "/lib/" + QFileInfo( libPath ).fileName();
}
#endif
QgsDebugMsg( "libPath = " + libPath );
mLibrary.setFileName( libPath );
if ( !mLibrary.load() )
{
QgsDebugMsg( "Cannot load original GRASS library" );
fatal( "Cannot load true GRASS library, path: " + libPath );
return;
}
}
Expand All @@ -113,11 +138,11 @@ void QgsGrassGisLib::warning( QString msg )

void * QgsGrassGisLib::resolve( const char * symbol )
{
//QgsDebugMsg( QString("symbol = %1").arg(symbol));
QgsDebugMsg( QString( "symbol = %1" ).arg( symbol ) );
void * fn = mLibrary.resolve( symbol );
if ( !fn )
{
QgsDebugMsg( "Cannot resolve symbol" );
fatal( "Cannot resolve symbol " + QString( symbol ) );
}
return fn;
}
Expand Down Expand Up @@ -175,6 +200,9 @@ int GRASS_LIB_EXPORT QgsGrassGisLib::G__gisinit( const char * version, const cha
// Read projection if set
//mCrs.createFromOgcWmsCrs( "EPSG:900913" );
QString crsStr = getenv( "QGIS_GRASS_CRS" );

QgsDebugMsg( "Setting CRS to " + crsStr );

if ( !crsStr.isEmpty() )
{
if ( !mCrs.createFromProj4( crsStr ) )
Expand Down Expand Up @@ -225,14 +253,23 @@ int GRASS_LIB_EXPORT QgsGrassGisLib::G__gisinit( const char * version, const cha
G_set_window( &window );
#endif

QString regionStr = getenv( "GRASS_REGION" );
if ( regionStr.isEmpty() )
{
fatal( "GRASS_REGION environment variable not set" );
}

QgsDebugMsg( "Getting region via true lib from GRASS_REGION: " + regionStr );
// GRASS true lib reads GRASS_REGION environment variable
G_get_window( &mWindow );

mExtent = QgsRectangle( mWindow.west, mWindow.south, mWindow.east, mWindow.north );
mRows = mWindow.rows;
mColumns = mWindow.cols;
mXRes = mExtent.width() / mColumns;
mYRes = mExtent.height() / mColumns;


QgsDebugMsg( "End" );
return 0;
}

Expand Down Expand Up @@ -321,6 +358,25 @@ char GRASS_LIB_EXPORT *QgsGrassGisLib::G_find_cell2( const char * name, const ch
return qstrdup( ms.toAscii() ); // memory lost
}

char GRASS_LIB_EXPORT *G__file_name( char *path, const char *element, const char *name, const char *mapset )
{
Q_UNUSED( path );
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

char *G__file_name_misc( char *path, const char *dir, const char *element, const char *name, const char *mapset )
{
Q_UNUSED( path );
Q_UNUSED( dir );
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

char GRASS_LIB_EXPORT *G_find_cell2( const char* name, const char *mapset )
{
return QgsGrassGisLib::instance()->G_find_cell2( name, mapset );
Expand All @@ -332,6 +388,40 @@ char GRASS_LIB_EXPORT *G_find_cell( char * name, const char * mapset )
return G_find_cell2( name, mapset );
}

char GRASS_LIB_EXPORT *G_find_file( const char *element, char *name, const char *mapset )
{
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

char GRASS_LIB_EXPORT *G_find_file2( const char *element, char *name, const char *mapset )
{
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

char GRASS_LIB_EXPORT *G_find_file_misc( const char *dir, const char *element, char *name, const char *mapset )
{
Q_UNUSED( dir );
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

char GRASS_LIB_EXPORT *G_find_file_misc2( const char *dir, const char *element, char *name, const char *mapset )
{
Q_UNUSED( dir );
Q_UNUSED( element );
Q_UNUSED( name );
Q_UNUSED( mapset );
return NULL;
}

QgsGrassGisLib::Raster QgsGrassGisLib::raster( QString name )
{
QgsDebugMsg( "name = " + name );
Expand Down Expand Up @@ -512,6 +602,11 @@ int GRASS_LIB_EXPORT G_open_cell_new( const char *name )
return QgsGrassGisLib::instance()->G_open_raster_new( name, CELL_TYPE );
}

int GRASS_LIB_EXPORT G_open_fp_cell_new( const char *name )
{
return QgsGrassGisLib::instance()->G_open_raster_new( name, FCELL_TYPE );
}

RASTER_MAP_TYPE QgsGrassGisLib::G_raster_map_type( const char *name, const char *mapset )
{
Q_UNUSED( mapset );
Expand Down Expand Up @@ -764,6 +859,24 @@ int GRASS_LIB_EXPORT G_get_map_row_nomask( int fd, CELL * buf, int row )
return G_get_map_row( fd, buf, row );
}

int QgsGrassGisLib::G_get_null_value_row( int fd, char *flags, int row )
{
FCELL *buf = G_allocate_f_raster_buf();
QgsGrassGisLib::instance()->readRasterRow( fd, buf, row, FCELL_TYPE, false );

for ( int i = 0; i < mColumns; i++ )
{
flags[i] = G_is_f_null_value( &buf[i] ) ? 1 : 0;
}
G_free( buf );
return 1;
}

int GRASS_LIB_EXPORT G_get_null_value_row( int fd, char *flags, int row )
{
return QgsGrassGisLib::instance()->G_get_null_value_row( fd, flags, row );
}

int QgsGrassGisLib::G_put_raster_row( int fd, const void *buf, RASTER_MAP_TYPE data_type )
{
Raster rast = mRasters.value( fd );
Expand Down Expand Up @@ -895,16 +1008,54 @@ double QgsGrassGisLib::G_database_units_to_meters_factor( void )
}
}

double QgsGrassGisLib::G_area_of_cell_at_row( int row )
{
double yMax = mExtent.yMaximum() - row * mYRes;
double yMin = yMax - mYRes;
QgsRectangle rect( mExtent.xMinimum(), yMin, mExtent.xMinimum() + mXRes, yMax );
QgsGeometry* geo = QgsGeometry::fromRect( rect );
double area = mDistanceArea.measure( geo );
delete geo;
if ( !mCrs.geographicFlag() )
{
area *= qPow( G_database_units_to_meters_factor(), 2 );
}
return area;
}

double GRASS_LIB_EXPORT G_area_of_cell_at_row( int row )
{
return QgsGrassGisLib::instance()->G_area_of_cell_at_row( row );
}

double GRASS_LIB_EXPORT G_database_units_to_meters_factor( void )
{
return QgsGrassGisLib::instance()->G_database_units_to_meters_factor();
}

int QgsGrassGisLib::G_begin_cell_area_calculations( void )
{
if ( mCrs.geographicFlag() ) return 2; // non-planimetric
return 1; // planimetric
}

int GRASS_LIB_EXPORT G_begin_cell_area_calculations( void )
{
return QgsGrassGisLib::instance()->G_begin_cell_area_calculations();
}

int GRASS_LIB_EXPORT G_begin_distance_calculations( void )
{
return 1; // nothing to do
}

int GRASS_LIB_EXPORT G_begin_geodesic_distance( double a, double e2 )
{
Q_UNUSED( a );
Q_UNUSED( e2 );
return 0; // nothing to do
}

// Distance in meters
double QgsGrassGisLib::G_distance( double e1, double n1, double e2, double n2 )
{
Expand All @@ -930,6 +1081,44 @@ int GRASS_LIB_EXPORT G_legal_filename( const char *s )
return 1;
}

int QgsGrassGisLib::G_set_geodesic_distance_lat1( double lat1 )
{
mLat1 = lat1;
return 0;
}

int QgsGrassGisLib::G_set_geodesic_distance_lat2( double lat2 )
{
mLat2 = lat2;
return 0;
}

int GRASS_LIB_EXPORT G_set_geodesic_distance_lat1( double lat1 )
{
return QgsGrassGisLib::instance()->G_set_geodesic_distance_lat1( lat1 );
}

int GRASS_LIB_EXPORT G_set_geodesic_distance_lat2( double lat2 )
{
return QgsGrassGisLib::instance()->G_set_geodesic_distance_lat2( lat2 );
}

double QgsGrassGisLib::G_geodesic_distance_lon_to_lon( double lon1, double lon2 )
{
double dist = mDistanceArea.measureLine( QgsPoint( lon1, mLat1 ), QgsPoint( lon2, mLat2 ) );
// TODO: not sure about this
if ( !mCrs.geographicFlag() )
{
dist *= G_database_units_to_meters_factor();
}
return dist;
}

double GRASS_LIB_EXPORT G_geodesic_distance_lon_to_lon( double lon1, double lon2 )
{
return QgsGrassGisLib::instance()->G_geodesic_distance_lon_to_lon( lon1, lon2 );
}

QgsRasterBlock::DataType QgsGrassGisLib::qgisRasterType( RASTER_MAP_TYPE grassType )
{
switch ( grassType )
Expand Down Expand Up @@ -993,6 +1182,12 @@ int G_asprintf( char **out, const char *fmt, ... )
return ret;
}

int GRASS_LIB_EXPORT G__temp_element( char *element )
{
Q_UNUSED( element );
return 0;
}

char GRASS_LIB_EXPORT *G_tempfile( void )
{
QTemporaryFile file( "qgis-grass-temp.XXXXXX" );
Expand Down Expand Up @@ -1030,6 +1225,14 @@ int GRASS_LIB_EXPORT G_quantize_fp_map_range( const char *name, const char *maps
return 1;
}

int GRASS_LIB_EXPORT G_read_cats( const char *name, const char *mapset, struct Categories *pcats )
{
Q_UNUSED( name );
Q_UNUSED( mapset );
G_init_raster_cats( "Cats", pcats );
return 0;
}

int GRASS_LIB_EXPORT G_read_raster_cats( const char *name, const char *mapset, struct Categories *pcats )
{
Q_UNUSED( name );
Expand Down Expand Up @@ -1102,3 +1305,36 @@ int GRASS_LIB_EXPORT G_make_aspect_fp_colors( struct Colors *colors, DCELL min,
return 1; // OK
}

int GRASS_LIB_EXPORT G_check_overwrite( int argc, char **argv )
{
Q_UNUSED( argc );
Q_UNUSED( argv );
return 1; // overwrite
}

char GRASS_LIB_EXPORT *G_fully_qualified_name( const char *name, const char *mapset )
{
Q_UNUSED( mapset );
return G_store( name );
}

char GRASS_LIB_EXPORT *G_ask_cell_new( const char *prompt, char *name )
{
Q_UNUSED( prompt );
Q_UNUSED( name );
return NULL;
}

char GRASS_LIB_EXPORT *G_ask_cell_old( const char *prompt, char *name )
{
Q_UNUSED( prompt );
Q_UNUSED( name );
return NULL;
}

int GRASS_LIB_EXPORT G_remove( const char *element, const char *name )
{
Q_UNUSED( element );
Q_UNUSED( name );
return 1;
}
14 changes: 14 additions & 0 deletions src/providers/grass/qgsgrassgislib.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,27 @@ class GRASS_LIB_EXPORT QgsGrassGisLib
char *G_find_cell2( const char * name, const char * mapset );
int G_open_cell_old( const char *name, const char *mapset );
int G_open_raster_new( const char *name, RASTER_MAP_TYPE wr_type );
int G_open_fp_cell_new( const char *name );
int G_close_cell( int fd );
RASTER_MAP_TYPE G_raster_map_type( const char *name, const char *mapset );
RASTER_MAP_TYPE G_get_raster_map_type( int fd );
//int G_raster_map_is_fp( const char *name, const char *mapset );
int G_read_fp_range( const char *name, const char *mapset, struct FPRange *drange );

int readRasterRow( int fd, void * buf, int row, RASTER_MAP_TYPE data_type, bool noDataAsZero = false );
int G_get_null_value_row( int fd, char *flags, int row );
int G_put_raster_row( int fd, const void *buf, RASTER_MAP_TYPE data_type );
int G_get_cellhd( const char *name, const char *mapset, struct Cell_head *cellhd );

double G_area_of_cell_at_row( int row );
double G_database_units_to_meters_factor( void );
int G_begin_cell_area_calculations( void );
double G_distance( double e1, double n1, double e2, double n2 );

int G_set_geodesic_distance_lat1( double lat1 );
int G_set_geodesic_distance_lat2( double lat2 );
double G_geodesic_distance_lon_to_lon( double lon1, double lon2 );

/** Get QGIS raster type for GRASS raster type */
QgsRasterBlock::DataType qgisRasterType( RASTER_MAP_TYPE grassType );

Expand Down Expand Up @@ -131,9 +139,15 @@ class GRASS_LIB_EXPORT QgsGrassGisLib
int mRows;
/** Current region columns */
int mColumns;
/** X resolution */
double mXRes;
/** Y resolution */
double mYRes;
/** Current coordinate reference system */
QgsCoordinateReferenceSystem mCrs;
QgsDistanceArea mDistanceArea;
/** lat1, lat2 used for geodesic distance calculation */
double mLat1, mLat2;
};

#endif // QGSGRASSGISLIB_H