Compare commits
101 Commits
59 changed files with 7300 additions and 897 deletions
@ -1,8 +1,11 @@ |
|||||||
*.[od] |
*.[od] |
||||||
*.so |
*.so |
||||||
include/grammatical.h |
*.kdev4 |
||||||
src/parser/grammatical.cpp |
.kdev4/* |
||||||
include/lexical.h |
/include/grammatical.h |
||||||
src/parser/lexical.cpp |
/src/parser/grammatical.cpp |
||||||
src/makemap |
/include/lexical.h |
||||||
modules/test/* |
/src/parser/lexical.cpp |
||||||
|
/src/makemap |
||||||
|
/bin/* |
||||||
|
/modules/test/* |
||||||
|
@ -0,0 +1,126 @@ |
|||||||
|
cmake_minimum_required(VERSION 2.8.5) |
||||||
|
|
||||||
|
# Make sure the user doesn't play dirty with symlinks |
||||||
|
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) |
||||||
|
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) |
||||||
|
|
||||||
|
# Disallow in-source builds |
||||||
|
if(${srcdir} STREQUAL ${bindir}) |
||||||
|
message(FATAL_ERROR "In-source builds are not allowed." |
||||||
|
" Please create a directory and run cmake from there, passing the path" |
||||||
|
" to this source directory as the last argument. This process created" |
||||||
|
" the file `CMakeCache.txt' and the directory `CMakeFiles' in ${srcdir}." |
||||||
|
" Please remove them.") |
||||||
|
endif() |
||||||
|
|
||||||
|
project(gmt_makemap CXX) |
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE) |
||||||
|
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel" FORCE) |
||||||
|
endif() |
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/" CACHE INTERNAL "Location of our custom CMake modules." FORCE) |
||||||
|
|
||||||
|
include_directories(include) |
||||||
|
|
||||||
|
# Checking compiler options |
||||||
|
set(default_options -Wall) |
||||||
|
set(linker_options -Wall) |
||||||
|
include(CheckCXXCompilerFlag) |
||||||
|
set(saved_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) |
||||||
|
# C++11 is required |
||||||
|
CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X) |
||||||
|
if(COMPILER_SUPPORTS_CXX11) |
||||||
|
set(default_options ${default_options} -std=c++11) |
||||||
|
elseif(COMPILER_SUPPORTS_CXX0X) |
||||||
|
set(default_options ${default_options} -std=c++0x) |
||||||
|
else() |
||||||
|
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") |
||||||
|
endif() |
||||||
|
# Link time optimization check |
||||||
|
set(CMAKE_REQUIRED_FLAGS -flto) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-flto COMPILER_SUPPORTS_FLTO) |
||||||
|
if(COMPILER_SUPPORTS_FLTO AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||||
|
set(default_options ${default_options} -flto) |
||||||
|
set(linker_options ${linker_options} -flto) |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
# Clang can use lto only with gold linker |
||||||
|
if(NOT COMPILER_SUPPORTS_FLTO) |
||||||
|
set(CMAKE_REQUIRED_FLAGS -flto\ -fuse-ld=gold) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-flto\ -fuse-ld=gold COMPILER_SUPPORTS_FLTO_GOLD) |
||||||
|
if(COMPILER_SUPPORTS_FLTO_GOLD AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||||
|
set(default_options ${default_options} -flto) |
||||||
|
set(linker_options ${linker_options} -flto\ -fuse-ld=gold) |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
endif() |
||||||
|
# Dwarf-4 support check |
||||||
|
set(CMAKE_REQUIRED_FLAGS -gdwarf-4) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-gdwarf-4 COMPILER_SUPPORTS_DWARF4) |
||||||
|
if(COMPILER_SUPPORTS_DWARF4 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) |
||||||
|
set(default_options ${default_options} -gdwarf-4) |
||||||
|
set(linker_options ${linker_options} -gdwarf-4) |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
# -ipo flag check (Intel compiler link time optimization) |
||||||
|
set(CMAKE_REQUIRED_FLAGS -ipo) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-ipo COMPILER_SUPPORTS_IPO) |
||||||
|
if(COMPILER_SUPPORTS_IPO AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||||
|
set(default_options ${default_options} -ipo) |
||||||
|
set(linker_options ${linker_options} -ipo) |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
# Default hidden visibility check |
||||||
|
set(CMAKE_REQUIRED_FLAGS -fvisibility=hidden) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-fvisibility=hidden COMPILER_SUPPORTS_HIDDEN) |
||||||
|
if(COMPILER_SUPPORTS_HIDDEN) |
||||||
|
set(default_options ${default_options} -fvisibility=hidden) |
||||||
|
set(linker_options ${linker_options} -fvisibility=hidden) |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
# Export dynamic. Required as modules mast call functions from main programm |
||||||
|
set(CMAKE_REQUIRED_FLAGS -Wl,--export-dynamic) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-Wl,--export-dynamic COMPILER_SUPPORTS_EXPORTDYNAMIC) |
||||||
|
if(COMPILER_SUPPORTS_EXPORTDYNAMIC) |
||||||
|
set(linker_options ${linker_options} -Wl,--export-dynamic) |
||||||
|
else() |
||||||
|
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no support of --export-dynamic. Please use a different C++ compiler.") |
||||||
|
endif() |
||||||
|
unset(CMAKE_REQUIRED_FLAGS) |
||||||
|
add_compile_options(${default_options}) |
||||||
|
set(CMAKE_REQUIRED_FLAGS ${saved_CMAKE_REQUIRED_FLAGS}) |
||||||
|
|
||||||
|
file(GLOB modules modules/*) |
||||||
|
file(GLOB extramodules extramodules/*) |
||||||
|
|
||||||
|
set(STATIC_MODULES "") |
||||||
|
|
||||||
|
set(CMAKE_SHARED_MODULE_PREFIX "") |
||||||
|
|
||||||
|
foreach(ext ${modules}) |
||||||
|
if(EXISTS ${ext}/CMakeLists.txt) |
||||||
|
string(REGEX REPLACE .*/ "" modname ${ext}) |
||||||
|
option(MODULE_${modname}_BUILD "Build module ${modname}" ON) |
||||||
|
option(MODULE_${modname}_STATIC "Link module ${modname} statically in gmt_makemap" ON) |
||||||
|
mark_as_advanced(FORCE MODULE_${modname}_STATIC) |
||||||
|
if(MODULE_${modname}_BUILD) |
||||||
|
add_subdirectory(modules/${modname}) |
||||||
|
endif() |
||||||
|
endif() |
||||||
|
endforeach(ext) |
||||||
|
|
||||||
|
foreach(ext ${extramodules}) |
||||||
|
if(EXISTS ${ext}/CMakeLists.txt) |
||||||
|
string(REGEX REPLACE .*/ "" modname ${ext}) |
||||||
|
option(MODULE_${modname}_BUILD "Build module ${modname}" ON) |
||||||
|
option(MODULE_${modname}_STATIC "Link module ${modname} statically in gmt_makemap" ON) |
||||||
|
mark_as_advanced(FORCE MODULE_${modname}_STATIC) |
||||||
|
if(MODULE_${modname}_BUILD) |
||||||
|
add_subdirectory(extramodules/${modname}) |
||||||
|
endif() |
||||||
|
endif() |
||||||
|
endforeach(ext) |
||||||
|
|
||||||
|
add_subdirectory(src) |
@ -0,0 +1,11 @@ |
|||||||
|
set(moddir ${CMAKE_CURRENT_SOURCE_DIR}) |
||||||
|
include(${moddir}/ModuleSetup.cmake OPTIONAL) |
||||||
|
file(GLOB srcs *.cpp) |
||||||
|
if(MODULE_${modname}_STATIC) |
||||||
|
set(STATIC_MODULES ${STATIC_MODULES} ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) |
||||||
|
else() |
||||||
|
include_directories(${MODULE_ADDITIONAL_INCLUDES}) |
||||||
|
add_library(${modname} MODULE ${srcs} ${MODULE_ADDITIONAL_SOURCES}) |
||||||
|
target_link_libraries(${modname} ${linker_options} ${MODULE_ADDITIONAL_LIBRARIES}) |
||||||
|
endif() |
||||||
|
|
@ -0,0 +1,114 @@ |
|||||||
|
# Locate GMT |
||||||
|
# |
||||||
|
# This module accepts the following environment variables: |
||||||
|
# |
||||||
|
# GMT_DIR or GMT_ROOT - Specify the location of GMT |
||||||
|
# |
||||||
|
# This module defines the following CMake variables: |
||||||
|
# |
||||||
|
# GMT_FOUND - True if libgmt is found |
||||||
|
# GMT_LIBRARY - A variable pointing to the GMT library |
||||||
|
# GMT_INCLUDE_DIR - Where to find the headers |
||||||
|
|
||||||
|
# Created by Michael Uleysky. Based on FindGDAL.cmake created by Eric Wing. |
||||||
|
# This makes the presumption that you are include gmt.h like |
||||||
|
# |
||||||
|
#include "gmt.h" |
||||||
|
|
||||||
|
if (DEFINED GMT_ROOT AND NOT GMT_ROOT) |
||||||
|
set (GMT_LIBRARY "" CACHE INTERNAL "") |
||||||
|
set (GMT_INCLUDE_DIR "" CACHE INTERNAL "") |
||||||
|
return() |
||||||
|
endif (DEFINED GMT_ROOT AND NOT GMT_ROOT) |
||||||
|
|
||||||
|
if (UNIX AND NOT GMT_FOUND) |
||||||
|
# Use gmt-config to obtain the library version (this should hopefully |
||||||
|
# allow us to -lGMT5.x.y where x.y are correct version) |
||||||
|
find_program (GMT_CONFIG gmt-config |
||||||
|
HINTS |
||||||
|
${GMT_DIR} |
||||||
|
${GMT_ROOT} |
||||||
|
$ENV{GMT_DIR} |
||||||
|
$ENV{GMT_ROOT} |
||||||
|
PATH_SUFFIXES bin |
||||||
|
PATHS |
||||||
|
/sw # Fink |
||||||
|
/opt/local # DarwinPorts |
||||||
|
/opt/csw # Blastwave |
||||||
|
/opt/gmt |
||||||
|
/opt/GMT |
||||||
|
/opt |
||||||
|
/usr/local |
||||||
|
) |
||||||
|
|
||||||
|
if (GMT_CONFIG) |
||||||
|
execute_process (COMMAND ${GMT_CONFIG} --cflags |
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE |
||||||
|
OUTPUT_VARIABLE GMT_CONFIG_CFLAGS) |
||||||
|
if (GMT_CONFIG_CFLAGS) |
||||||
|
string (REGEX MATCHALL "-I[^ ]+" _GMT_dashI ${GMT_CONFIG_CFLAGS}) |
||||||
|
string (REGEX REPLACE "-I" "" _GMT_includepath "${_GMT_dashI}") |
||||||
|
string (REGEX REPLACE "-I[^ ]+" "" _GMT_cflags_other ${GMT_CONFIG_CFLAGS}) |
||||||
|
endif (GMT_CONFIG_CFLAGS) |
||||||
|
execute_process (COMMAND ${GMT_CONFIG} --libs |
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE |
||||||
|
OUTPUT_VARIABLE GMT_CONFIG_LIBS) |
||||||
|
if (GMT_CONFIG_LIBS) |
||||||
|
string (REGEX MATCHALL "-l[^ ]+" _GMT_dashl ${GMT_CONFIG_LIBS}) |
||||||
|
string (REGEX REPLACE "-l" "" _GMT_lib "${_GMT_dashl}") |
||||||
|
string (REGEX MATCHALL "-L[^ ]+" _GMT_dashL ${GMT_CONFIG_LIBS}) |
||||||
|
string (REGEX REPLACE "-L" "" _GMT_libpath "${_GMT_dashL}") |
||||||
|
endif (GMT_CONFIG_LIBS) |
||||||
|
endif (GMT_CONFIG) |
||||||
|
endif (UNIX AND NOT GMT_FOUND) |
||||||
|
|
||||||
|
find_path (GMT_INCLUDE_DIR gmt.h |
||||||
|
HINTS |
||||||
|
${_GMT_includepath} |
||||||
|
${GMT_DIR} |
||||||
|
${GMT_ROOT} |
||||||
|
$ENV{GMT_DIR} |
||||||
|
$ENV{GMT_ROOT} |
||||||
|
PATH_SUFFIXES |
||||||
|
include/GMT |
||||||
|
include/GMT |
||||||
|
include |
||||||
|
PATHS |
||||||
|
~/Library/Frameworks/GMT.framework/Headers |
||||||
|
/Library/Frameworks/GMT.framework/Headers |
||||||
|
/sw # Fink |
||||||
|
/opt/local # DarwinPorts |
||||||
|
/opt/csw # Blastwave |
||||||
|
/opt/gmt |
||||||
|
/opt/GMT |
||||||
|
/opt |
||||||
|
/usr/local |
||||||
|
) |
||||||
|
|
||||||
|
find_library (GMT_LIBRARY |
||||||
|
NAMES ${_GMT_lib} gmt gmt5.1 gmt5.1.2 gmt5.1.3 |
||||||
|
HINTS |
||||||
|
${GMT_DIR} |
||||||
|
${GMT_ROOT} |
||||||
|
$ENV{GMT_DIR} |
||||||
|
$ENV{GMT_ROOT} |
||||||
|
${_GMT_libpath} |
||||||
|
PATH_SUFFIXES lib |
||||||
|
PATHS |
||||||
|
~/Library/Frameworks/GMT.framework |
||||||
|
/Library/Frameworks/GMT.framework |
||||||
|
/sw # Fink |
||||||
|
/opt/local # DarwinPorts |
||||||
|
/opt/csw # Blastwave |
||||||
|
/opt/gmt |
||||||
|
/opt/GMT |
||||||
|
/opt |
||||||
|
/usr/local |
||||||
|
) |
||||||
|
|
||||||
|
include (FindPackageHandleStandardArgs) |
||||||
|
find_package_handle_standard_args (GMT DEFAULT_MSG GMT_LIBRARY GMT_INCLUDE_DIR) |
||||||
|
|
||||||
|
set (GMT_LIBRARIES ${GMT_LIBRARY}) |
||||||
|
set (GMT_INCLUDE_DIRS ${GMT_INCLUDE_DIR}) |
||||||
|
|
@ -0,0 +1,34 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
MAKEMAP="${1:-/tmp/save/build/src/makemap}" |
||||||
|
TPATH=tests |
||||||
|
|
||||||
|
SCRW=`tput cols` |
||||||
|
|
||||||
|
set -o pipefail |
||||||
|
|
||||||
|
for n in "$TPATH"/*; do |
||||||
|
status=`cat $n|grep "# Status: "|sed "s/# Status: //"` |
||||||
|
desc=`cat $n|grep "# Description: "|sed "s/# Description: //"` |
||||||
|
hash=`cat $n|grep "# Output hash: "|sed "s/.*: //"` |
||||||
|
while [ ${#desc} -lt $((SCRW-5)) ]; do desc+=" "; done |
||||||
|
echo -n "$desc" |
||||||
|
t=`mktemp` |
||||||
|
grep -v -E "# .*: " "$n">$t |
||||||
|
thash=`$MAKEMAP "$t" 2>&1 | sha256sum|sed "s/ .*//"` |
||||||
|
ret=$? |
||||||
|
if [ "$status" == "ok" ]; then |
||||||
|
if [ "$hash" == "$thash" -a "$ret" == "0" ]; then |
||||||
|
echo -e "\033[32mOk \033[0m" |
||||||
|
else |
||||||
|
echo -e "\033[31mFail\033[0m" |
||||||
|
fi |
||||||
|
else |
||||||
|
if [ "$hash" == "$thash" -a "$ret" != "0" ]; then |
||||||
|
echo -e "\033[32mOk \033[0m" |
||||||
|
else |
||||||
|
echo -e "\033[31mFail\033[0m" |
||||||
|
fi |
||||||
|
fi |
||||||
|
rm $t |
||||||
|
done |
@ -1,20 +1,119 @@ |
|||||||
|
#ifndef BUILTIN_H |
||||||
|
#define BUILTIN_H |
||||||
|
#include <cmath> |
||||||
#include "object.h" |
#include "object.h" |
||||||
|
|
||||||
ObjectBase* Arifm_Add(const ObjectList* input); |
template<class O> |
||||||
ObjectBase* Arifm_Sub(const ObjectList* input); |
struct Valued |
||||||
ObjectBase* Arifm_Mul(const ObjectList* input); |
{ |
||||||
ObjectBase* Arifm_Div(const ObjectList* input); |
double operator ()(const O* q, bool* isok) {return q->Value();} |
||||||
ObjectBase* Arifm_Pow(const ObjectList* input); |
}; |
||||||
ObjectBase* Arifm_Neg(const ObjectList* input); |
|
||||||
ObjectBase* Arifm_Pos(const ObjectList* input); |
template<> |
||||||
|
struct Valued<ObjectString> |
||||||
|
{ |
||||||
|
double operator ()(const ObjectString* q, bool* isok) {double d=0; if(!str2double(q->Value(),&d)) *isok=false; return d;} |
||||||
|
}; |
||||||
|
|
||||||
template<class T> |
template<class O> |
||||||
ObjectBase* Get(const ObjectList* input) |
struct Valuei |
||||||
{ |
{ |
||||||
if(input->Size()!=2) return 0; |
int64_t operator ()(const O* q, bool* isok) {return q->Value();} |
||||||
const ObjectBase* ob=input->At(0); |
}; |
||||||
const ObjectBase* name=input->At(1); |
|
||||||
if( (!IS_OTYPE(ob,T)) || (!IS_OTYPE(name,ObjectString)) ) return 0; |
template<> |
||||||
|
struct Valuei<ObjectString> |
||||||
|
{ |
||||||
|
int64_t operator ()(const ObjectString* q, bool* isok) {int64_t i=0; if(!str2int(q->Value(),&i)) *isok=false; return i;} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
template<class T> class OpAdd {public: static T V(T a1, T a2) {return a1+a2;}}; |
||||||
|
template<class T> class OpSub {public: static T V(T a1, T a2) {return a1-a2;}}; |
||||||
|
template<class T> class OpMul {public: static T V(T a1, T a2) {return a1*a2;}}; |
||||||
|
template<class T> class OpDiv {public: static T V(T a1, T a2) {return a1/a2;}}; |
||||||
|
template<class T> class OpPow {public: static T V(T a1, T a2) {return pow(a1,a2);}}; |
||||||
|
template<class T> class OpNeg {public: static T V(T a) {return -a;}}; |
||||||
|
template<class T> class OpPos {public: static T V(T a) {return +a;}}; |
||||||
|
|
||||||
|
template<template<typename> class Op, bool intArifm=true> |
||||||
|
const ObjectBase* Arifm2(const ObjectList* input) |
||||||
|
{ |
||||||
|
if(input->Size()!=2) return new ObjectError("Arifmetic binary operator","incorrect number of arguments"); |
||||||
|
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
||||||
|
OBTypeM<Valuei,ObjectInt,ObjectString> i1(arg1), i2(arg2); |
||||||
|
OBTypeM<Valued,ObjectReal,ObjectInt,ObjectString> r1(arg1), r2(arg2); |
||||||
|
bool isok1=true, isok2=true; |
||||||
|
|
||||||
|
// Integer arifmetic
|
||||||
|
if(i1 && i2 && intArifm) |
||||||
|
{ |
||||||
|
int64_t v1=i1(&isok1),v2=i2(&isok2); |
||||||
|
if(isok1 && isok2) return new ObjectInt(Op<int64_t>::V(v1,v2)); |
||||||
|
} |
||||||
|
|
||||||
|
isok1=isok2=true; |
||||||
|
// Real arifmetic
|
||||||
|
if(r1 && r2) |
||||||
|
{ |
||||||
|
double v1=r1(&isok1),v2=r2(&isok2); |
||||||
|
if(isok1 && isok2) return new ObjectReal(Op<double>::V(v1,v2)); |
||||||
|
} |
||||||
|
|
||||||
|
// Analyze error
|
||||||
|
// Check first argument
|
||||||
|
switch(r1.Error()) |
||||||
|
{ |
||||||
|
case(OBTypeErr::OK): if(!isok1) return new ObjectError("Arifmetic binary operator","failed conversion of first argument to double"); else break; |
||||||
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic binary operator","first argument is nullptr"); // Impossible case
|
||||||
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic binary operator","first argument has incorrect type"); |
||||||
|
} |
||||||
|
|
||||||
|
// Firs argument is ok, check second
|
||||||
|
switch(r2.Error()) |
||||||
|
{ |
||||||
|
case(OBTypeErr::OK): if(!isok2) return new ObjectError("Arifmetic binary operator","failed conversion of second argument to double"); else break; |
||||||
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic binary operator","second argument is nullptr"); // Impossible case
|
||||||
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic binary operator","second argument has incorrect type"); |
||||||
|
} |
||||||
|
|
||||||
|
return new ObjectError("Arifmetic binary operator","unknown error"); // Impossible case
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
template<template<typename> class Op, bool intArifm=true> |
||||||
|
const ObjectBase* Arifm1(const ObjectList* input) |
||||||
|
{ |
||||||
|
if(input->Size()!=1) return new ObjectError("Arifmetic unary operator","incorrect number of arguments"); |
||||||
|
const ObjectBase *arg=input->At(0); |
||||||
|
OBTypeM<Valuei,ObjectInt,ObjectString> i(arg); |
||||||
|
OBTypeM<Valued,ObjectReal,ObjectString> r(arg); |
||||||
|
bool isok; |
||||||
|
|
||||||
|
// Integer arifmetic
|
||||||
|
isok=true; |
||||||
|
if(i && intArifm) |
||||||
|
{ |
||||||
|
int64_t v=i(&isok); |
||||||
|
if(isok) return new ObjectInt(Op<int64_t>::V(v)); |
||||||
|
} |
||||||
|
|
||||||
|
// Real arifmetic
|
||||||
|
isok=true; |
||||||
|
if(r) |
||||||
|
{ |
||||||
|
double v=r(&isok); |
||||||
|
if(isok) return new ObjectReal(Op<double>::V(v)); |
||||||
|
} |
||||||
|
|
||||||
|
// Analyze error
|
||||||
|
switch(r.Error()) |
||||||
|
{ |
||||||
|
case(OBTypeErr::OK): if(!isok) return new ObjectError("Arifmetic unary operator","failed conversion of argument to double"); else break; |
||||||
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic unary operator","argument is nullptr"); // Impossible case
|
||||||
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic unary operator","argument has incorrect type"); |
||||||
|
} |
||||||
|
|
||||||
return dynamic_cast<const T*>(ob)->Get(dynamic_cast<const ObjectString*>(name)->Value()); |
return new ObjectError("Arifmetic unary operator","unknown error"); // Impossible case
|
||||||
} |
} |
||||||
|
#endif |
||||||
|
@ -1,84 +1,111 @@ |
|||||||
#ifndef OBJECT_H |
#ifndef OBJECT_H |
||||||
#define OBJECT_H |
#define OBJECT_H |
||||||
#include <stdio.h> |
|
||||||
#include <errno.h> |
#include <errno.h> |
||||||
#include <string.h> |
|
||||||
#include <inttypes.h> |
#include <inttypes.h> |
||||||
|
#include <stack> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
#include "common.h" |
#include "common.h" |
||||||
|
|
||||||
// Class for storing identifiers
|
// Bison location
|
||||||
class OId: public ObjectBase |
struct grammatic_location |
||||||
{ |
{ |
||||||
std::string name; |
struct incloc |
||||||
|
{ |
||||||
|
int line,column; |
||||||
|
std::string filename; |
||||||
|
}; |
||||||
|
int first_line; |
||||||
|
int first_column; |
||||||
|
int last_line; |
||||||
|
int last_column; |
||||||
|
std::list<struct incloc> incstack; |
||||||
|
std::string filename; |
||||||
|
}; |
||||||
|
|
||||||
|
class StackElem |
||||||
|
{ |
||||||
|
StackElem()=delete; |
||||||
|
StackElem(const StackElem&)=delete; |
||||||
public: |
public: |
||||||
OId(const std::string* t):name(*t) {} |
enum Type {TYPE_EMPTY,TYPE_BEGINLIST,TYPE_ENDLIST,TYPE_MKPAIR,TYPE_OBJECT,TYPE_VARIABLE,TYPE_FUNCTION}; |
||||||
~OId() {} |
StackElem(Type t, const struct grammatic_location& loc, const char* s=nullptr):type(t),obj(nullptr),location(loc) |
||||||
// Pure virtual overrides
|
|
||||||
ObjectBase* Copy() const override |
|
||||||
{ |
{ |
||||||
COUT(WARNING)<<"OId::Copy: this call must never be happens."<<std::endl; |
if(TYPE_BEGINLIST==t || TYPE_ENDLIST==t) return; |
||||||
return new OId(&name); |
if( (TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) && nullptr!=s) name=s; |
||||||
|
else type=TYPE_EMPTY; |
||||||
} |
} |
||||||
bool Print() const override {return false;} |
StackElem(Type t, const struct grammatic_location& loc, const std::string& s):type(t),obj(nullptr),location(loc) |
||||||
std::string Type() const override {return "IDENT";} |
|
||||||
|
|
||||||
// Non-default overrides
|
|
||||||
std::string Dump() const override {return name;}; |
|
||||||
ObjectBase* Evaluate(bool* err) override |
|
||||||
{ |
{ |
||||||
COUT(ERROR)<<"Variable "<<name<<" still not defined."<<std::endl; |
if(TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) name=s; |
||||||
*err=true; |
else type=TYPE_EMPTY; |
||||||
return 0; |
|
||||||
} |
} |
||||||
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override |
StackElem(ObjectBase* o, const struct grammatic_location& loc):type(TYPE_OBJECT),obj(o),location(loc) {} |
||||||
|
~StackElem() {if(TYPE_OBJECT==type) delete obj;} |
||||||
|
StackElem(StackElem&& s):type(s.type),name(s.name),location(s.location) |
||||||
{ |
{ |
||||||
if(vname==Name()) return ob->Copy(); |
if(TYPE_OBJECT==type) |
||||||
else return 0; |
{ |
||||||
|
// Simple copy of pointer
|
||||||
|
obj=s.obj; |
||||||
|
// Prevent destruction of ObjectBase in StackElem destructor
|
||||||
|
s.type=TYPE_EMPTY; |
||||||
|
} |
||||||
} |
} |
||||||
void UsedIdents(UsedType& ids) const override {ids.insert(name);} |
|
||||||
|
|
||||||
// Own functions
|
|
||||||
std::string Name() const {return name;} |
|
||||||
// void SetName(const std::string& s) {name=s;}
|
|
||||||
}; |
|
||||||
|
|
||||||
// Class for storing functions
|
const ObjectBase* Object() const {return isObject()?obj:nullptr;} |
||||||
class OFunc: public ObjectBase |
// Detach object
|
||||||
{ |
const ObjectBase* PickObject() |
||||||
std::string name; |
|
||||||
ObjectList* args; |
|
||||||
public: |
|
||||||
OFunc(const std::string* t, ObjectBase* p):name(*t) |
|
||||||
{ |
|
||||||
if(IS_OTYPE(p,ObjectList)) args=dynamic_cast<ObjectList*>(p); |
|
||||||
else args=new ObjectList(p); |
|
||||||
} |
|
||||||
OFunc(const char* t, ObjectBase* p):name(t) |
|
||||||
{ |
{ |
||||||
if(IS_OTYPE(p,ObjectList)) args=dynamic_cast<ObjectList*>(p); |
if(isObject()) |
||||||
else args=new ObjectList(p); |
{ |
||||||
|
type=TYPE_EMPTY; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
else return nullptr; |
||||||
} |
} |
||||||
~OFunc() {if(args!=0) delete args;} |
bool ReplaceByObject(const ObjectBase* ob) |
||||||
// Pure virtual overrides
|
|
||||||
ObjectBase* Copy() const override |
|
||||||
{ |
{ |
||||||
COUT(WARNING)<<"OFunc::Copy: this call must never be happens."<<std::endl; |
if(isObject()) {delete ob; return false;} |
||||||
return new OFunc(&name,args->Copy()); |
type=TYPE_OBJECT; |
||||||
|
obj=ob; |
||||||
|
return true; |
||||||
} |
} |
||||||
bool Print() const override {return false;} |
std::string Name() const {return (isVar() || isFunc() || isMKPair())?name:std::string();} |
||||||
std::string Type() const override {return "FUNC";} |
bool isObject() const {return (TYPE_OBJECT==type);} |
||||||
|
bool isVar() const {return (TYPE_VARIABLE==type);} |
||||||
|
bool isFunc() const {return (TYPE_FUNCTION==type);} |
||||||
|
bool isBList() const {return (TYPE_BEGINLIST==type);} |
||||||
|
bool isEList() const {return (TYPE_ENDLIST==type);} |
||||||
|
bool isMKPair() const {return (TYPE_MKPAIR==type);} |
||||||
|
const struct grammatic_location& Location() const {return location;} |
||||||
|
Type T() const {return type;} |
||||||
|
|
||||||
// Non-default overrides
|
private: |
||||||
std::string Dump() const override {return Name()+args->Dump();}; |
Type type; |
||||||
ObjectBase* Evaluate(bool* err) override; |
const ObjectBase* obj; |
||||||
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override {return args->ReplaceVar(vname,ob);} |
std::string name; |
||||||
void UsedFuncs(UsedType& funcs) const override {funcs.insert(name); args->UsedFuncs(funcs);} |
struct grammatic_location location; |
||||||
void UsedIdents(UsedType& ids) const override {args->UsedIdents(ids);} |
|
||||||
|
|
||||||
// Own functions
|
|
||||||
std::string Name() const {return name;} |
|
||||||
// void SetName(std::string s) {name=s;}
|
|
||||||
}; |
}; |
||||||
|
|
||||||
|
typedef std::list<StackElem> ExecExpr; |
||||||
|
|
||||||
|
inline StackElem SEBList(const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_BEGINLIST,loc);} |
||||||
|
inline StackElem SEEList(const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_ENDLIST,loc);} |
||||||
|
inline StackElem SEObj(ObjectBase* o, const struct grammatic_location& loc) {return StackElem(o,loc);} |
||||||
|
inline StackElem SEMKPair(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_MKPAIR,loc,s);} |
||||||
|
inline StackElem SEVar(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_VARIABLE,loc,s);} |
||||||
|
inline StackElem SEFunc(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_FUNCTION,loc,s);} |
||||||
|
inline StackElem SEMKPair(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_MKPAIR,loc,*s);} |
||||||
|
inline StackElem SEVar(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_VARIABLE,loc,*s);} |
||||||
|
inline StackElem SEFunc(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_FUNCTION,loc,*s);} |
||||||
|
|
||||||
|
std::string DumpExprE(const ExecExpr& exp); |
||||||
|
std::string DumpExpr(const ExecExpr& exp); |
||||||
|
UsedType UsedVars(const ExecExpr& exp); |
||||||
|
UsedType UsedFuncs(const ExecExpr& exp); |
||||||
|
const ObjectBase* Evaluate(ExecExpr& exp, bool* err); |
||||||
|
//inline void ReplaceVar(ExecExpr& exp, const std::string& var, ObjectBase* ob) {for(auto& se: exp) if(se.isVar() && var==se.Name()) se.ReplaceByObject(ob);}
|
||||||
|
void ReplaceVar(ExecExpr& exp, const std::string& var, const ObjectBase* ob);// {for(auto& se: exp) if(se.isVar() && var==se.Name()) se.ReplaceByObject(ob);}
|
||||||
|
|
||||||
#endif |
#endif |
||||||
|
@ -0,0 +1,34 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
name="$1" |
||||||
|
desc="$2" |
||||||
|
TLOC="${3:-/tmp/save/test}" |
||||||
|
MAKEMAP="${4:-/tmp/save/build/src/makemap}" |
||||||
|
|
||||||
|
if [ -f tests/"$name" ]; then |
||||||
|
echo "Test $name already exist." |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
if [ ! -f "$TLOC" ]; then |
||||||
|
echo "Configuration file $TLOC not found." |
||||||
|
exit 2 |
||||||
|
fi |
||||||
|
|
||||||
|
if [ ! -x "$MAKEMAP" ]; then |
||||||
|
echo "Can't exec file $MAKEMAP." |
||||||
|
exit 3 |
||||||
|
fi |
||||||
|
|
||||||
|
echo "# Description: $desc" >tests/$name |
||||||
|
if "$MAKEMAP" "$TLOC" &>/dev/null; then |
||||||
|
hash=`"$MAKEMAP" "$TLOC" 2>/dev/null|sha256sum|sed "s/ .*//"` |
||||||
|
status=ok |
||||||
|
else |
||||||
|
hash=`"$MAKEMAP" "$TLOC" 2>&1|sha256sum|sed "s/ .*//"` |
||||||
|
status=fail |
||||||
|
fi |
||||||
|
echo "# Status: $status" >>tests/$name |
||||||
|
echo "# Output hash: $hash" >>tests/$name |
||||||
|
cat "$TLOC" >>tests/$name |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
/gmt_filter_headfoot.cpp |
||||||
|
/gmt_filter_headfoot.h |
@ -0,0 +1,3 @@ |
|||||||
|
cmake_minimum_required(VERSION 2.8.5) |
||||||
|
|
||||||
|
include(BuildModule) |
@ -0,0 +1,24 @@ |
|||||||
|
find_package(FLEX REQUIRED) |
||||||
|
FLEX_TARGET(GMT_hfScanner ${moddir}/modgmt_filter_headfoot.l ${CMAKE_CURRENT_BINARY_DIR}/modgmt_filter_headfoot.cpp COMPILE_FLAGS "--header-file=${CMAKE_CURRENT_BINARY_DIR}/modgmt_filter_headfoot.h") |
||||||
|
set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES modgmt_filter_headfoot.h) |
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
||||||
|
|
||||||
|
find_package(GMT REQUIRED) |
||||||
|
|
||||||
|
# Search ghostscript |
||||||
|
if(NOT GHOSTSCRIPT_ROOT_DIR) |
||||||
|
set(GHOSTSCRIPT_ROOT_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH "Ghostscript root path") |
||||||
|
endif() |
||||||
|
mark_as_advanced(CLEAR GHOSTSCRIPT_ROOT_DIR) |
||||||
|
find_path(GHOSTSCRIPT_INCLUDES NAMES ghostscript/gdevdsp.h ghostscript/iapi.h HINTS ${GHOSTSCRIPT_ROOT_DIR} ${CMAKE_INSTALL_PREFIX}) |
||||||
|
find_library(GHOSTSCRIPT_LIBRARY gs HINTS ${GHOSTSCRIPT_ROOT_DIR} ${CMAKE_INSTALL_PREFIX}) |
||||||
|
if(NOT GHOSTSCRIPT_INCLUDES) |
||||||
|
message(FATAL_ERROR "Ghostscript includes not found!") |
||||||
|
endif() |
||||||
|
if(NOT GHOSTSCRIPT_LIBRARY) |
||||||
|
message(FATAL_ERROR "Ghostscript library not found!") |
||||||
|
endif() |
||||||
|
|
||||||
|
set(MODULE_ADDITIONAL_SOURCES ${FLEX_GMT_hfScanner_OUTPUTS}) |
||||||
|
set(MODULE_ADDITIONAL_INCLUDES ${GMT_INCLUDE_DIR} ${GHOSTSCRIPT_INCLUDES}) |
||||||
|
set(MODULE_ADDITIONAL_LIBRARIES ${GMT_LIBRARIES} ${GHOSTSCRIPT_LIBRARY}) |
@ -0,0 +1,35 @@ |
|||||||
|
MODLIBS+=-lgmt |
||||||
|
|
||||||
|
GMT_FLSOURCE=modgmt_filter_headfoot.cpp |
||||||
|
GMT_FLHEADERS=$(subst .cpp,.h,$(GMT_FLSOURCE)) |
||||||
|
|
||||||
|
ifeq ($(subst ,$(GMT_FLSOURCE),$(SOURCE)),$(SOURCE)) |
||||||
|
SOURCE+=$(GMT_FLSOURCE) |
||||||
|
MODSOURCE+=modules/gmt/$(GMT_FLSOURCE) |
||||||
|
MODHEADERS+=modules/gmt/$(GMT_FLHEADERS) |
||||||
|
endif |
||||||
|
|
||||||
|
ifdef MODULE |
||||||
|
modgmt_filters.d: modgmt_filter_headfoot.h |
||||||
|
|
||||||
|
modgmt_filter_headfoot.cpp: modgmt_filter_headfoot.l |
||||||
|
flex -o $@ --header-file=modgmt_filter_headfoot.h $< |
||||||
|
[ -f modgmt_filter_headfoot.h ] && touch modgmt_filter_headfoot.h |
||||||
|
|
||||||
|
modgmt_filter_headfoot.h: modgmt_filter_headfoot.l modgmt_filter_headfoot.cpp |
||||||
|
|
||||||
|
.PHONY: gmt_clean |
||||||
|
|
||||||
|
clean: gmt_clean |
||||||
|
|
||||||
|
gmt_clean: |
||||||
|
rm -f $(GMT_FLSOURCE) $(GMT_FLHEADERS) |
||||||
|
|
||||||
|
else |
||||||
|
|
||||||
|
modules/gmt/modgmt_filter_headfoot.cpp: modules/gmt/modgmt_filter_headfoot.l |
||||||
|
make -C modules/gmt -f ../../Makefile MODULE=gmt modgmt_filter_headfoot.cpp |
||||||
|
|
||||||
|
modules/gmt/modgmt_filter_headfoot.h: modules/gmt/modgmt_filter_headfoot.cpp |
||||||
|
|
||||||
|
endif |
@ -0,0 +1,58 @@ |
|||||||
|
#include "modgmt.h" |
||||||
|
#include "modgmt_func.h" |
||||||
|
#include "modgmt_internals.h" |
||||||
|
#include "modgmt_gsfuncs.h" |
||||||
|
#include "modgmt_map.h" |
||||||
|
|
||||||
|
// Initialisation function
|
||||||
|
int gmt_module_init(void* p) |
||||||
|
{ |
||||||
|
// Fill header and footer
|
||||||
|
void* gmtapi; |
||||||
|
int ret=0; |
||||||
|
|
||||||
|
gmtapi=GMT_Create_Session("gmt_makemap",2,GMTMODE,0); |
||||||
|
if(0==gmtapi) return 1; |
||||||
|
if(0==ret) ret=callgmtmodule(gmtapi,"psclip","-C -P -K",&header,gmt_filter_headfoot); |
||||||
|
if(0==ret) ret=callgmtmodule(gmtapi,"psclip","-C -P -O",&footer,gmt_filter_headfoot); |
||||||
|
GMT_Destroy_Session(gmtapi); |
||||||
|
if(0!=ret) return ret; |
||||||
|
|
||||||
|
gmt_projection::FillProjNames(); |
||||||
|
if(!gmt_font::FillFontNames()) return 1; |
||||||
|
|
||||||
|
RegisterFunction("GMT_Header",GMT_Header); |
||||||
|
RegisterFunction("GMT_Footer",GMT_Footer); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTCoord>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTRegion>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTProjection>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTColor>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTDash>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTPen>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTFont>); |
||||||
|
RegisterFunction("GET",Get<ObjectGMTLayer>); |
||||||
|
|
||||||
|
RegisterFunction("Coord",GMT_Type<struct gmt_coord>); |
||||||
|
RegisterFunction("Region",GMT_Type<struct gmt_region>); |
||||||
|
RegisterFunction("Projection",GMT_Type<struct gmt_projection>); |
||||||
|
RegisterFunction("Color",GMT_Type<struct gmt_color>); |
||||||
|
RegisterFunction("ColorGray",GMT_ColorGray); |
||||||
|
RegisterFunction("ColorRGB",GMT_ColorRGB); |
||||||
|
RegisterFunction("ColorHSV",GMT_ColorHSV); |
||||||
|
RegisterFunction("ColorCMYK",GMT_ColorCMYK); |
||||||
|
RegisterFunction("Pen",GMT_Type<struct gmt_pen>); |
||||||
|
RegisterFunction("Font",GMT_Type<struct gmt_font>); |
||||||
|
RegisterFunction("Shift",GMT_LayerShift); |
||||||
|
RegisterFunction("DrawFrame",GMT_DrawFrame); |
||||||
|
RegisterFunction("Map",GMT_Map); |
||||||
|
RegisterFunction("Convert2PDF",GMT_Convert2PDF); |
||||||
|
RegisterFunction("Convert2PNG",GMT_Convert2PNG); |
||||||
|
RegisterFunction("Convert2JPG",GMT_Convert2JPG); |
||||||
|
RegisterFunction("Convert2JPEG",GMT_Convert2JPG); |
||||||
|
|
||||||
|
CheckGhostscriptAbilities(); |
||||||
|
// Calculating bounding box is critical
|
||||||
|
if(!gs_abilities.havebbox) return 1; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
#ifndef MODGMT_H |
||||||
|
#define MODGMT_H |
||||||
|
#include "common.h" |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
EXPORT int gmt_module_init(void* p); |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@ |
|||||||
|
#ifndef MODGMT_COLORNAMES_H |
||||||
|
#define MODGMT_COLORNAMES_H |
||||||
|
|
||||||
|
struct colorname {const char *name; double r; double g; double b; }; |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
class ColorHash |
||||||
|
{ |
||||||
|
private: |
||||||
|
static inline unsigned int colornamehash (const char *str, unsigned int len); |
||||||
|
public: |
||||||
|
static const struct colorname *in_colors_set (const char *str, unsigned int len); |
||||||
|
}; |
||||||
|
|
||||||
|
inline unsigned int |
||||||
|
ColorHash::colornamehash (const char *str, unsigned int len) |
||||||
|
{ |
||||||
|
static const unsigned short asso_values[] = |
||||||
|
{ |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 666, 27, |
||||||
|
26, 23, 22, 789, 588, 587, 501, 436, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 61, 96, 222, 98, 22, |
||||||
|
117, 22, 561, 559, 22, 708, 179, 301, 42, 101, |
||||||
|
242, 46, 23, 22, 116, 171, 821, 809, 2728, 169, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 61, 96, 222, |
||||||
|
98, 22, 117, 22, 561, 559, 22, 708, 179, 301, |
||||||
|
42, 101, 242, 46, 23, 22, 116, 171, 821, 809, |
||||||
|
2728, 169, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, |
||||||
|
2728, 2728, 2728, 2728, 2728, 2728 |
||||||
|
}; |
||||||
|
int hval = len; |
||||||
|
|
||||||
|
switch (hval) |
||||||
|
{ |
||||||
|
default: |
||||||
|
hval += asso_values[(unsigned char)str[12]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 12: |
||||||
|
hval += asso_values[(unsigned char)str[11]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 11: |
||||||
|
case 10: |
||||||
|
case 9: |
||||||
|
case 8: |
||||||
|
hval += asso_values[(unsigned char)str[7]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 7: |
||||||
|
hval += asso_values[(unsigned char)str[6]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 6: |
||||||
|
hval += asso_values[(unsigned char)str[5]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 5: |
||||||
|
hval += asso_values[(unsigned char)str[4]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 4: |
||||||
|
case 3: |
||||||
|
hval += asso_values[(unsigned char)str[2]]; |
||||||
|
/*FALLTHROUGH*/ |
||||||
|
case 2: |
||||||
|
case 1: |
||||||
|
hval += asso_values[(unsigned char)str[0]]; |
||||||
|
break; |
||||||
|
} |
||||||
|
return hval + asso_values[(unsigned char)str[len - 1]]; |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,135 @@ |
|||||||
|
// From grayscale
|
||||||
|
struct gmt_color Gray2RGB() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=RGB; |
||||||
|
color.r=color.g=color.b=gray; |
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color Gray2HSV() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=HSV; |
||||||
|
color.hue=0; |
||||||
|
color.saturation=0; |
||||||
|
color.value=gray/255.0; |
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color Gray2CMYK() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=CMYK; |
||||||
|
color.cyan=color.magenta=color.yellow=0; |
||||||
|
color.black=(1.0-gray/255.0)*100.0; |
||||||
|
return color; |
||||||
|
} |
||||||
|
|
||||||
|
// From RGB
|
||||||
|
struct gmt_color RGB2Gray() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=GRAY; |
||||||
|
color.gray=0.2126*r+0.7152*g+0.0722*b; |
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color RGB2HSV() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=HSV; |
||||||
|
double rr=r/255.0,gg=g/255.0,bb=b/255.0; |
||||||
|
double cmax=std::max(rr,std::max(gg,bb)); |
||||||
|
double cmin=std::min(rr,std::min(gg,bb)); |
||||||
|
double delta=cmax-cmin; |
||||||
|
|
||||||
|
if(0==delta) color.hue=0; |
||||||
|
else if(cmax==rr) |
||||||
|
{ |
||||||
|
double x=(gg-bb)/delta; |
||||||
|
color.hue=x-floor(x/6.0)*6.0; |
||||||
|
} |
||||||
|
else if(cmax==gg) color.hue=(bb-rr)/delta+2.0; |
||||||
|
else if(cmax==bb) color.hue=(rr-gg)/delta+4.0; |
||||||
|
color.hue*=60.0; |
||||||
|
color.saturation=(0==cmax)?0:(delta/cmax); |
||||||
|
color.value=cmax; |
||||||
|
|
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color RGB2CMYK() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=CMYK; |
||||||
|
double rr=r/255.0,gg=g/255.0,bb=b/255.0; |
||||||
|
double k=1.0-std::max(rr,std::max(gg,bb)); |
||||||
|
|
||||||
|
color.black=k; |
||||||
|
color.cyan=(1.0-rr-k)/(1.0-k); |
||||||
|
color.magenta=(1.0-gg-k)/(1.0-k); |
||||||
|
color.yellow=(1.0-bb-k)/(1.0-k); |
||||||
|
if(0.0==1.0-k) color.cyan=color.magenta=color.yellow=0.0; |
||||||
|
color.black*=100.0; |
||||||
|
color.cyan*=100.0; |
||||||
|
color.magenta*=100.0; |
||||||
|
color.yellow*=100.0; |
||||||
|
|
||||||
|
return color; |
||||||
|
} |
||||||
|
|
||||||
|
// From HSV
|
||||||
|
struct gmt_color HSV2Gray() const |
||||||
|
{ |
||||||
|
return HSV2RGB().RGB2Gray(); |
||||||
|
} |
||||||
|
struct gmt_color HSV2RGB() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=RGB; |
||||||
|
double c=saturation*value; |
||||||
|
double x=c*(1.0-fabs((hue/60.0)-floor((hue/60.0)/2.0)*2.0-1.0)); |
||||||
|
double m=value-c; |
||||||
|
|
||||||
|
if(0.0 <=hue && 60.0 >hue) {color.r=c; color.g=x; color.b=0;} |
||||||
|
if(60.0 <=hue && 120.0>hue) {color.r=x; color.g=c; color.b=0;} |
||||||
|
if(120.0<=hue && 180.0>hue) {color.r=0; color.g=c; color.b=x;} |
||||||
|
if(180.0<=hue && 240.0>hue) {color.r=0; color.g=x; color.b=c;} |
||||||
|
if(240.0<=hue && 300.0>hue) {color.r=x; color.g=0; color.b=c;} |
||||||
|
if(300.0<=hue &&360.0>=hue) {color.r=c; color.g=0; color.b=x;} |
||||||
|
color.r+=m; color.g+=m; color.b+=m; |
||||||
|
color.r*=255; color.g*=255; color.b*=255; |
||||||
|
|
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color HSV2CMYK() const |
||||||
|
{ |
||||||
|
return HSV2RGB().RGB2CMYK(); |
||||||
|
} |
||||||
|
|
||||||
|
// From CMYK
|
||||||
|
struct gmt_color CMYK2Gray() const |
||||||
|
{ |
||||||
|
return CMYK2RGB().RGB2Gray(); |
||||||
|
} |
||||||
|
struct gmt_color CMYK2RGB() const |
||||||
|
{ |
||||||
|
struct gmt_color color; |
||||||
|
color.transparency=transparency; |
||||||
|
color.model=RGB; |
||||||
|
double cc=cyan/100.0,mm=magenta/100.0,yy=yellow/100.0,kk=black/100.0; |
||||||
|
|
||||||
|
color.r=255.0*(1.0-cc)*(1.0-kk); |
||||||
|
color.g=255.0*(1.0-mm)*(1.0-kk); |
||||||
|
color.b=255.0*(1.0-yy)*(1.0-kk); |
||||||
|
|
||||||
|
return color; |
||||||
|
} |
||||||
|
struct gmt_color CMYK2HSV() const |
||||||
|
{ |
||||||
|
return CMYK2RGB().RGB2HSV(); |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
%option 8bit reentrant |
||||||
|
%option warn |
||||||
|
%option yylineno |
||||||
|
%option noyywrap |
||||||
|
%option prefix="gmt_filter_headfoot" |
||||||
|
%option extra-type="std::string*" |
||||||
|
%option nounput |
||||||
|
%x NOTCOMMENTS |
||||||
|
%x SETUP |
||||||
|
%x ENDHEAD |
||||||
|
%x ENDFOOTER |
||||||
|
|
||||||
|
%{ |
||||||
|
#include <string> |
||||||
|
// flex use register keyword, but it deprecated in C++11. |
||||||
|
#define register |
||||||
|
// Get rid of warning on unused function |
||||||
|
#define YY_NO_INPUT |
||||||
|
// struct yyguts_t defined in each flex output file, this emits warning at linking stage |
||||||
|
#define yyguts_t gmt_filter_headfootguts_t |
||||||
|
#define yyterminate {return 0;} |
||||||
|
%} |
||||||
|
|
||||||
|
/* |
||||||
|
For header: |
||||||
|
1. Remove all comments from begin to %%EndComments inclusively |
||||||
|
2. Remove %%Page, %%BeginPageSetup, %%EndPageSetup DSC comments |
||||||
|
3. Remove all content between %%BeginSetup and %%EndSetup (skip setpagedevice) |
||||||
|
4. Skip code after %%EndPageSetup (draw code) |
||||||
|
|
||||||
|
For footer: |
||||||
|
1. Remove all before %%PageTrailer, but not %%PageTrailer itself |
||||||
|
*/ |
||||||
|
|
||||||
|
%% |
||||||
|
<INITIAL>%%EndComments\n BEGIN(NOTCOMMENTS); |
||||||
|
<INITIAL>%%PageTrailer\n yyextra->append(yytext,yyleng); BEGIN(ENDFOOTER); |
||||||
|
<NOTCOMMENTS>%%Page:.*\n |
||||||
|
<NOTCOMMENTS>%%BeginPageSetup.*\n |
||||||
|
<NOTCOMMENTS>%%EndPageSetup.*\n BEGIN(ENDHEAD); |
||||||
|
<NOTCOMMENTS>%%BeginSetup.*\n BEGIN(SETUP); |
||||||
|
<NOTCOMMENTS,ENDFOOTER>.*\n yyextra->append(yytext,yyleng); |
||||||
|
<SETUP>%%EndSetup.*\n BEGIN(NOTCOMMENTS); |
||||||
|
<INITIAL,SETUP,ENDHEAD>.*\n |
||||||
|
<*><<EOF>> yyterminate; |
||||||
|
%% |
@ -0,0 +1,31 @@ |
|||||||
|
#include "modgmt_filters.h" |
||||||
|
#include "modgmt_filter_headfoot.h" |
||||||
|
|
||||||
|
int gmt_filter_default(int fd, std::string* res, void* p) |
||||||
|
{ |
||||||
|
ssize_t br; |
||||||
|
char buffer[4096]; |
||||||
|
|
||||||
|
do |
||||||
|
{ |
||||||
|
br=read(fd,buffer,4096); |
||||||
|
res->append(buffer,br); |
||||||
|
} while(0!=br); |
||||||
|
close(fd); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int gmt_filter_headfoot(int fd, std::string* res, void* p) |
||||||
|
{ |
||||||
|
yyscan_t scanner; |
||||||
|
FILE* in; |
||||||
|
|
||||||
|
in=fdopen(fd,"r"); |
||||||
|
gmt_filter_headfootlex_init_extra(res,&scanner); |
||||||
|
gmt_filter_headfootset_in(in,scanner); |
||||||
|
gmt_filter_headfootlex(scanner); |
||||||
|
gmt_filter_headfootlex_destroy(scanner); |
||||||
|
fclose(in); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
#ifndef MODGMT_FILTERS_H |
||||||
|
#define MODGMT_FILTERS_H |
||||||
|
#include <unistd.h> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
typedef int (*gmt_filter)(int, std::string*, void*); |
||||||
|
|
||||||
|
int gmt_filter_default(int, std::string*, void*); |
||||||
|
int gmt_filter_headfoot(int, std::string*, void*); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,308 @@ |
|||||||
|
#include "modgmt_func.h" |
||||||
|
|
||||||
|
static double AutoStep(double b, double e) |
||||||
|
{ |
||||||
|
double n=pow(10.0,ceil(log10(e-b)-1.0)); |
||||||
|
double steps[]={0.5,1,2,5,10,0}; |
||||||
|
double div=0.0; |
||||||
|
uint i=0; |
||||||
|
|
||||||
|
do if((e-b)*steps[i]/n<10.0) div=n/steps[i]; while(0.0!=steps[++i]); |
||||||
|
return div; |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_Header(const ObjectList* input) |
||||||
|
{ |
||||||
|
return new ObjectString(header); |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_Footer(const ObjectList* input) |
||||||
|
{ |
||||||
|
return new ObjectString(footer); |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_ColorGray(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct gmt_color c; |
||||||
|
RPosPar<Base2RGB> g("gray"); |
||||||
|
OPosPar<Base2TransD> t("transparency",0.0); |
||||||
|
|
||||||
|
ParsePositionalParameters params(input,g,t); |
||||||
|
if(!params) return new ObjectError("ColorGray",params.Error()); |
||||||
|
|
||||||
|
c.model=gmt_color::GRAY; |
||||||
|
c.gray=g; c.transparency=t; |
||||||
|
|
||||||
|
return new ObjectGMTColor(c); |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_ColorRGB(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct gmt_color c; |
||||||
|
|
||||||
|
RPosPar<Base2RGB> r("red"),g("green"),b("blue"); |
||||||
|
OPosPar<Base2TransD> t("transparency",0.0); |
||||||
|
|
||||||
|
ParsePositionalParameters params(input,r,g,b,t); |
||||||
|
if(!params) return new ObjectError("ColorRGB",params.Error()); |
||||||
|
|
||||||
|
c.model=gmt_color::RGB; |
||||||
|
c.r=r; c.g=g; c.b=b; c.transparency=t; |
||||||
|
|
||||||
|
return new ObjectGMTColor(c); |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_ColorHSV(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct gmt_color c; |
||||||
|
|
||||||
|
RPosPar<Base2Hue> h("hue"); |
||||||
|
RPosPar<Base2SV> s("saturation"), v("value"); |
||||||
|
OPosPar<Base2TransD> t("transparency",0.0); |
||||||
|
|
||||||
|
ParsePositionalParameters params(input,h,s,v,t); |
||||||
|
if(!params) return new ObjectError("ColorHSV",params.Error()); |
||||||
|
|
||||||
|
c.model=gmt_color::HSV; |
||||||
|
c.hue=h; c.saturation=s; c.value=v; c.transparency=t; |
||||||
|
|
||||||
|
return new ObjectGMTColor(c); |
||||||
|
} |
||||||
|
|
||||||
|
const ObjectBase* GMT_ColorCMYK(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct gmt_color C; |
||||||
|
|
||||||
|
RPosPar<Base2CMYK> c("cyan"),m("magenta"),y("yellow"),k("black"); |
||||||
|
OPosPar<Base2TransD> t("transparency",0.0); |
||||||
|
|
||||||
|
ParsePositionalParameters params(input,c,m,y,k,t); |
||||||
|
if(!params) return new ObjectError("ColorCMYK",params.Error()); |
||||||
|
|
||||||
|
C.model=gmt_color::CMYK; |
||||||
|
C.cyan=c; C.magenta=m; C.yellow=y; C.black=k; C.transparency=t; |
||||||
|
|
||||||
|
return new ObjectGMTColor(C); |
||||||
|
} |
||||||
|
|
||||||
|
// Shifting layer
|
||||||
|
/*
|
||||||
|
Input: |
||||||
|
1) Three arguments, first is Layer, second and third are double. Interprets as new absolute position in cm. |
||||||
|
2) Pairs list. Names are l (layer), x, y, relx (rx), rely (ry). Pair with name l may be absent, in this case search in list and using as layer object with ObjectGMTLayer type. x and y are absolute positions in cm, relx and rely are shift from current position. x (y) and relx (rely) are mutually exlusive, but x (y) and rely (relx) can be used simultaneously. If position for some axis is absent, then this position is unchanged. |
||||||
|
*/ |
||||||
|
const ObjectBase* GMT_LayerShift(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct gmt_layer layer; |
||||||
|
std::string err; |
||||||
|
|
||||||
|
// Case 1
|
||||||
|
{ |
||||||
|
RPosPar<Base2Layer> l("layer"); |
||||||
|
OPosPar<Base2DoubleD> x("x",0.0), y("y",0.0); |
||||||
|
|
||||||
|
{ParsePositionalParameters params(input,l,x,y); if(!params) goto case2;} // Try case 2, if case 1 failed.
|
||||||
|
layer=l; layer.shiftx=x; layer.shifty=y; |
||||||
|
return new ObjectGMTLayer(layer); |
||||||
|
} |
||||||
|
|
||||||
|
case2: |
||||||
|
{ |
||||||
|
RNPar<Base2Layer> l("layer"); |
||||||
|
ONPar<Base2Double> x("x"),y("y"),rx("r[el]x"),ry("r[el]y"); |
||||||
|
|
||||||
|
{ParseNamedParameters params(input,l,x,y); if(!params) {err=params.Error(); goto fail;}} // Parsing error
|
||||||
|
|
||||||
|
// Check duplicate parameters
|
||||||
|
if(x.Exist() && rx.Exist()) {err="Only one of "+x.Name()+" or "+rx.Name()+" can be specified."; goto fail;} |
||||||
|
if(y.Exist() && ry.Exist()) {err="Only one of "+y.Name()+" or "+ry.Name()+" can be specified."; goto fail;} |
||||||
|
// Do shift
|
||||||
|
if( x.Exist()) layer.shiftx=x; |
||||||
|
if( y.Exist()) layer.shifty=y; |
||||||
|
if(rx.Exist()) layer.shiftx+=rx; |
||||||
|
if(ry.Exist()) layer.shifty+=ry; |
||||||
|
} |
||||||
|
|
||||||
|
return new ObjectGMTLayer(layer); |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("LayerShift",err); |
||||||
|
} |
||||||
|
|
||||||
|
// Draw frame with tics
|
||||||
|
/*
|
||||||
|
Input: pairs list. |
||||||
|
proj or projection or unnamed GMTProjection parameter - projection. This is mandatory argument. |
||||||
|
xtics - position of tics for x axis. Can be none, up, down or both. Default is down. |
||||||
|
ytics - position of tics for y axis. Can be none, left, right or both. Default is left. |
||||||
|
xint - tics interval for x axis. Numerical value or word auto. Default is auto. |
||||||
|
yint - tics interval for y axis. Numerical value or word auto. Default is auto. |
||||||
|
domain - coordinates domain. Can be pos (0:360), neg (-360:0) or center (-180:180) (only for geographic projections). Default is pos. |
||||||
|
mark - using letters (W, E, S, N) instead of sign for coordinates (only for geographic projections). Can be yes or no. Default is no. |
||||||
|
font - font using for annotations. Default is 12,Times-Roman,black. |
||||||
|
offset - distance from end of tick-mark to start of annotation in cm. Default is 0.18. |
||||||
|
framewidth - width of frame (only for geographic projections) in cm. Default is 0.1. |
||||||
|
framepen - pen for drawing frame. Default is 0.35,black. |
||||||
|
ticklen - lenght of tick-marks in cm. Default is 0.18. |
||||||
|
tickpen - pen for drawing ticks. Default is 0.3,black. |
||||||
|
trans or transparency - transparency level, double from 0 to 100. Default is 0 (opaque). |
||||||
|
model - transparency model, string. Choose from Color, ColorBurn, ColorDodge, Darken, Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, Overlay, Saturation, SoftLight, and Screen. Default is Normal. |
||||||
|
rx or relx - shift layer on x cm in horisontal direction. Default is 0. |
||||||
|
ry or rely - shift layer on y cm in vertical direction. Default is 0. |
||||||
|
*/ |
||||||
|
template<class O> |
||||||
|
using SConvertor=Convert2Struct<std::string, O>; |
||||||
|
template<class O> |
||||||
|
using DConvertor=Convert2Struct<double, O>; |
||||||
|
|
||||||
|
const ObjectBase* GMT_DrawFrame(const ObjectList* input) |
||||||
|
{ |
||||||
|
struct XYIntVal // Representing intervals for tics intervals
|
||||||
|
{ |
||||||
|
bool isauto; double val; |
||||||
|
XYIntVal():isauto(true),val(0.0) {} // Default is auto
|
||||||
|
}; |
||||||
|
|
||||||
|
class Base2TInt // Custom convertor class for xy tics intervals
|
||||||
|
{ |
||||||
|
public: |
||||||
|
using ValueType=struct XYIntVal; |
||||||
|
|
||||||
|
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err) |
||||||
|
{ |
||||||
|
ValueType ret; |
||||||
|
ret.isauto=false; |
||||||
|
|
||||||
|
OBTypeM<SConvertor,ObjectString> sp(ob); |
||||||
|
OBTypeM<DConvertor,ObjectReal,ObjectInt,ObjectString> dp(ob); |
||||||
|
// Check string "auto"
|
||||||
|
if(sp.Error()==OBTypeErr::OK) |
||||||
|
{ |
||||||
|
std::string s=sp(res,std::ref(err)); |
||||||
|
if(!res) {err="Unknown error"; goto fail;} // Impossible case
|
||||||
|
tolower(s); |
||||||
|
if("auto"==s) {ret.isauto=true; return ret;} |
||||||
|
} |
||||||
|
// Check double value
|
||||||
|
switch(dp.Error()) |
||||||
|
{ |
||||||
|
case(OBTypeErr::OK): |
||||||
|
{ |
||||||
|
ret.val=dp(res,std::ref(err)); |
||||||
|
if(ret.val<=0.0) {err="Tics interval must be greater the zero"; break;} |
||||||
|
return ret; |
||||||
|
}; |
||||||
|
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;} |
||||||
|
case(OBTypeErr::TYPEMISMATCH): {err="Can't convert "+ob->Type()+" to double: type mismatch"; break;} |
||||||
|
} |
||||||
|
fail: |
||||||
|
*res=false; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
std::string err,fakerr; |
||||||
|
std::string opts="-P -O -K "; |
||||||
|
|
||||||
|
struct gmt_layer layer; |
||||||
|
|
||||||
|
struct gmt_font deffont; |
||||||
|
struct gmt_pen defframepen,deftickpen; |
||||||
|
deffont.Convert("12,Times-Roman,black",fakerr); |
||||||
|
defframepen.Convert("0.35,black",fakerr); |
||||||
|
deftickpen.Convert("0.3,black",fakerr); |
||||||
|
|
||||||
|
RNFPar<Base2Proj,ObjectGMTProjection> proj("projection"); |
||||||
|
ONPar<Base2TInt> xint("x[ ]interval"), yint("y[ ]interval"); |
||||||
|
ONPar<Base2StringD> xtics("x[ ]tics[ ]position","down"), ytics("y[ ]t[ics[ ]position","left"); |
||||||
|
ONPar<Base2StringD> domain("domain","pos"); |
||||||
|
ONPar<Base2BoolD> mark("mark",false); |
||||||
|
ONPar<Base2FontD> font("font",deffont); |
||||||
|
ONPar<Base2DoubleD> offset("offset",0.18); |
||||||
|
ONPar<Base2NonNegD> framewidth("f[rame][ ]width",0.1); |
||||||
|
ONPar<Base2PenD> framepen("f[rame][ ]pen",defframepen), tickpen("t[icks][ ]pen",deftickpen); |
||||||
|
ONPar<Base2DoubleD> ticklen("t[icks][ ]length",0.18); |
||||||
|
ONPar<Base2TransD> transp("transparency",0.0); |
||||||
|
ONPar<Base2StringD> transpmodel("model","Normal"); |
||||||
|
ONPar<Base2DoubleD> rx("r[el]x",0.0),ry("r[el]y",0.0); |
||||||
|
|
||||||
|
ParseNamedParameters params(input,proj,xint,yint,xtics,ytics,domain,mark,font,offset,framewidth,framepen,tickpen,ticklen,transp,transpmodel,rx,ry); if(!params) {err=params.Error(); goto fail;} // Error parsing parameters
|
||||||
|
|
||||||
|
layer.proj=proj; // Get projection
|
||||||
|
opts+=layer.proj.Value()+" "; |
||||||
|
|
||||||
|
{ // Get tics intervals
|
||||||
|
XYIntVal dx=xint,dy=yint; |
||||||
|
opts+="-Bx"+ToString(dx.isauto?AutoStep(layer.proj.region.xb,layer.proj.region.xe):dx.val)+" -By"+ToString(dy.isauto?AutoStep(layer.proj.region.yb,layer.proj.region.ye):dy.val)+" "; |
||||||
|
} |
||||||
|
|
||||||
|
{ // Get xtics and ytics positions
|
||||||
|
std::string xt=xtics, yt=ytics; |
||||||
|
std::string xaxis, yaxis; |
||||||
|
TemplateComparator none("none"), both("both"); |
||||||
|
TemplateComparator up("up"), down("down"); |
||||||
|
TemplateComparator left("left"), right("right"); |
||||||
|
tolower(xt); tolower(yt); |
||||||
|
|
||||||
|
if(none.Compare(xt)) xaxis="sn"; |
||||||
|
if(down.Compare(xt)) xaxis="Sn"; |
||||||
|
if( up.Compare(xt)) xaxis="sN"; |
||||||
|
if(both.Compare(xt)) xaxis="SN"; |
||||||
|
|
||||||
|
if( none.Compare(yt)) yaxis="we"; |
||||||
|
if( left.Compare(yt)) yaxis="We"; |
||||||
|
if(right.Compare(yt)) yaxis="wE"; |
||||||
|
if( both.Compare(yt)) yaxis="WE"; |
||||||
|
|
||||||
|
if(xaxis.empty()) {err="Incorrect xtics position "+xtics.Value(); goto fail;} // Unknown value of xtics
|
||||||
|
if(yaxis.empty()) {err="Incorrect xtics position "+ytics.Value(); goto fail;} // Unknown value of ytics
|
||||||
|
opts+="-B"+xaxis+yaxis+" "; |
||||||
|
} |
||||||
|
|
||||||
|
{ // Get domain and mark
|
||||||
|
std::string dom=domain; |
||||||
|
std::string format; |
||||||
|
TemplateComparator p("positive"),n("negative"),c("centered"); |
||||||
|
tolower(dom); |
||||||
|
|
||||||
|
if(p.Compare(dom)) format="+ddd:mm:ss"; |
||||||
|
if(n.Compare(dom)) format="-ddd:mm:ss"; |
||||||
|
if(c.Compare(dom)) format="ddd:mm:ss"; |
||||||
|
if(format.empty()) {err="Incorrect domain value "+domain.Value(); goto fail;} // Unknown domain
|
||||||
|
|
||||||
|
if(mark) format+="F"; |
||||||
|
opts+="--FORMAT_GEO_MAP="+format+" "; |
||||||
|
} |
||||||
|
|
||||||
|
opts+="--FONT_ANNOT_PRIMARY="+font.Value().Value()+" "; // Get font
|
||||||
|
opts+="--MAP_ANNOT_OFFSET_PRIMARY="+ToString(offset.Value())+"c "; // Get offset
|
||||||
|
opts+="--MAP_FRAME_WIDTH="+ToString(framewidth.Value())+"c "; // Get framewidth
|
||||||
|
opts+="--MAP_FRAME_PEN="+framepen.Value().Value()+" "; // Get framepen
|
||||||
|
opts+="--MAP_TICK_LENGTH_PRIMARY="+ToString(ticklen.Value())+"c "; // Get ticklen
|
||||||
|
opts+="--MAP_TICK_PEN_PRIMARY="+tickpen.Value().Value()+" "; // Get tickpen
|
||||||
|
if(transp!=0) opts+="-t"+ToString(transp.Value())+" "; // Get transparency
|
||||||
|
opts+="--PS_TRANSPARENCY="+transpmodel.Value()+" "; // Get transparency model
|
||||||
|
|
||||||
|
// Get shift
|
||||||
|
layer.shiftx=rx; |
||||||
|
layer.shifty=ry; |
||||||
|
|
||||||
|
{ // Calling psbasemap
|
||||||
|
void* gmtapi; |
||||||
|
std::string* draw=new std::string; |
||||||
|
int ret; |
||||||
|
|
||||||
|
gmtapi=GMT_Create_Session("DrawFrame",2,GMTMODE,0); |
||||||
|
if(0==gmtapi) goto fail; // Can't create GMT GMT_Create_Session
|
||||||
|
ret=callgmtmodule(gmtapi,"psbasemap",opts,draw); |
||||||
|
GMT_Destroy_Session(gmtapi); |
||||||
|
if(0!=ret) {delete draw; goto fail;} // Psbasemap error
|
||||||
|
layer.data.reset(draw); |
||||||
|
} |
||||||
|
|
||||||
|
layer.creator="psbasemap "+opts; |
||||||
|
return new ObjectGMTLayer(layer); |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("DrawFrame",err); |
||||||
|
} |
@ -0,0 +1,168 @@ |
|||||||
|
#include <string.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include "common.h" |
||||||
|
#include "modgmt_gsfuncs.h" |
||||||
|
|
||||||
|
struct gs_abilities_struct gs_abilities; |
||||||
|
|
||||||
|
static int gs_callback_out(void *caller_handle, const char *buf, int len) |
||||||
|
{ |
||||||
|
struct gs_runtime* r=static_cast<struct gs_runtime*>(caller_handle); |
||||||
|
if(0!=r->out) r->out->append(buf,len); |
||||||
|
return len; |
||||||
|
} |
||||||
|
|
||||||
|
static int gs_callback_err(void *caller_handle, const char *buf, int len) |
||||||
|
{ |
||||||
|
struct gs_runtime* r=static_cast<struct gs_runtime*>(caller_handle); |
||||||
|
if(0!=r->err) r->err->append(buf,len); |
||||||
|
return len; |
||||||
|
} |
||||||
|
|
||||||
|
static int gs_callback_in(void *caller_handle, char *buf, int len) |
||||||
|
{ |
||||||
|
struct gs_runtime* r=static_cast<struct gs_runtime*>(caller_handle); |
||||||
|
if(r->pos>=r->in->length()) return 0; |
||||||
|
size_t rem=r->in->length()-r->pos; |
||||||
|
if(rem>static_cast<size_t>(len)) rem=len; |
||||||
|
memcpy(buf,r->in->c_str()+r->pos,rem); |
||||||
|
r->pos+=rem; |
||||||
|
return rem; |
||||||
|
} |
||||||
|
|
||||||
|
struct gsworkthreadpars |
||||||
|
{ |
||||||
|
struct gs_runtime* r; |
||||||
|
gs_callback input_callback; |
||||||
|
int fd; |
||||||
|
const std::string* opts; |
||||||
|
int ret; |
||||||
|
}; |
||||||
|
|
||||||
|
// This function call gs_* in separate thread, because ghostscript write to stdout
|
||||||
|
static void* gsworkthread(void* x) |
||||||
|
{ |
||||||
|
struct gsworkthreadpars* p=reinterpret_cast<struct gsworkthreadpars*>(x); |
||||||
|
WordList wl; |
||||||
|
if(-1==p->fd) wl=Split("-dSAFER -q -o/dev/null "+*(p->opts)+" -"); |
||||||
|
else wl=Split("-dSAFER -dDOINTERPOLATE -q -o/dev/fd/"+ToString(p->fd)+" "+*(p->opts)+" -"); |
||||||
|
int argc=wl.size()+1; |
||||||
|
char** argv; |
||||||
|
int i; |
||||||
|
void* gs; |
||||||
|
|
||||||
|
argv=new char*[argc]; |
||||||
|
argv[0]=new char[2]; argv[0][0]='G'; argv[0][1]=0; |
||||||
|
i=1; |
||||||
|
for(auto& opt: wl) |
||||||
|
{ |
||||||
|
argv[i]=new char[opt.length()+1]; |
||||||
|
memcpy(argv[i],opt.c_str(),opt.length()+1); |
||||||
|
i++; |
||||||
|
} |
||||||
|
|
||||||
|
p->ret=gsapi_new_instance(&gs,p->r); |
||||||
|
if(p->ret<0) goto end; |
||||||
|
gsapi_set_stdio(gs,p->input_callback?p->input_callback:gs_callback_in,gs_callback_out,gs_callback_err); |
||||||
|
p->ret=gsapi_init_with_args(gs,argc,argv); |
||||||
|
if(0==p->ret || e_Quit==p->ret) p->ret=gsapi_exit(gs); |
||||||
|
else gsapi_exit(gs); |
||||||
|
if(e_Quit==p->ret) p->ret=0; |
||||||
|
gsapi_delete_instance(gs); |
||||||
|
|
||||||
|
end: |
||||||
|
close(p->fd); |
||||||
|
for(i=0;i<argc;i++) delete[] argv[i]; |
||||||
|
delete[] argv; |
||||||
|
return &p->ret; |
||||||
|
} |
||||||
|
|
||||||
|
// Main function for prepare and run ghostscript
|
||||||
|
static int GhostRun(const std::string& opts, struct gs_runtime* r, std::string* out, gs_callback input=0) |
||||||
|
{ |
||||||
|
struct gsworkthreadpars wp; |
||||||
|
int* pret; |
||||||
|
int ret=0; |
||||||
|
|
||||||
|
wp.r=r; |
||||||
|
wp.input_callback=input; |
||||||
|
wp.opts=&opts; |
||||||
|
wp.ret=0; |
||||||
|
wp.fd=-1; |
||||||
|
|
||||||
|
if(0!=out) |
||||||
|
{ |
||||||
|
int pipefd[2]; |
||||||
|
pthread_t wthr; |
||||||
|
ssize_t br; |
||||||
|
char buffer[4096]; |
||||||
|
|
||||||
|
if(0!=pipe(pipefd)) {ret=-1; goto end;} |
||||||
|
wp.fd=pipefd[1]; |
||||||
|
|
||||||
|
out->erase(); |
||||||
|
pthread_create(&wthr,0,&gsworkthread,&wp); |
||||||
|
do |
||||||
|
{ |
||||||
|
br=read(pipefd[0],buffer,4096); |
||||||
|
out->append(buffer,br); |
||||||
|
} while(0!=br); |
||||||
|
close(pipefd[0]); |
||||||
|
out->shrink_to_fit(); |
||||||
|
pthread_join(wthr,reinterpret_cast<void**>(&pret)); |
||||||
|
} |
||||||
|
else pret=reinterpret_cast<int*>(gsworkthread(&wp)); |
||||||
|
|
||||||
|
end: |
||||||
|
if(0!=ret) return ret; |
||||||
|
return *pret; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// This function run ghostscript with input data in string
|
||||||
|
int GhostRun(const std::string& opts, const std::string& input, std::string* sout, std::string* serr, std::string* out) |
||||||
|
{ |
||||||
|
struct gs_runtime r; |
||||||
|
|
||||||
|
r.in=&input; |
||||||
|
r.pos=0; |
||||||
|
r.out=sout; |
||||||
|
r.err=serr; |
||||||
|
return GhostRun(opts,&r,out); |
||||||
|
} |
||||||
|
|
||||||
|
// This function run ghostscript with input data provided by callback function
|
||||||
|
int GhostRun(const std::string& opts, gs_callback input, void* inputdata, std::string* sout, std::string* serr, std::string* out) |
||||||
|
{ |
||||||
|
struct gs_runtime r; |
||||||
|
|
||||||
|
r.indata=inputdata; |
||||||
|
r.out=sout; |
||||||
|
r.err=serr; |
||||||
|
return GhostRun(opts,&r,out,input); |
||||||
|
} |
||||||
|
|
||||||
|
void CheckGhostscriptAbilities() |
||||||
|
{ |
||||||
|
std::string out; |
||||||
|
gs_abilities.havepdf=gs_abilities.havebbox=gs_abilities.havepngmono=gs_abilities.havepngmonod=gs_abilities.havepng16=gs_abilities.havepng256=gs_abilities.havepnggray=gs_abilities.havepng16m=gs_abilities.havejpeg=gs_abilities.havejpeggray=false; |
||||||
|
|
||||||
|
if(0!=GhostRun("-sDEVICE=nullpage","devicenames ==",&out,0,0)) return; |
||||||
|
|
||||||
|
WordList wl=Split(out,"[]/ \t"); |
||||||
|
for(auto& i:wl) |
||||||
|
{ |
||||||
|
if("pdfwrite"==i) gs_abilities.havepdf=true; |
||||||
|
if("bbox"==i) gs_abilities.havebbox=true; |
||||||
|
if("pngmono"==i) gs_abilities.havepngmono=true; |
||||||
|
if("pngmonod"==i) gs_abilities.havepngmonod=true; |
||||||
|
if("png16"==i) gs_abilities.havepng16=true; |
||||||
|
if("png256"==i) gs_abilities.havepng256=true; |
||||||
|
if("pnggray"==i) gs_abilities.havepnggray=true; |
||||||
|
if("png16m"==i) gs_abilities.havepng16m=true; |
||||||
|
if("jpeg"==i) gs_abilities.havejpeg=true; |
||||||
|
if("jpeggray"==i) gs_abilities.havejpeggray=true; |
||||||
|
} |
||||||
|
|
||||||
|
// gs_abilities.havepdf=(0==GhostRun("-sDEVICE=pdfwrite -dCompatibilityLevel=1.4","gsave 1 0 0 setrgbcolor 5 setlinewidth 100 100 moveto 200 200 lineto stroke grestore showpage",0,0,0));
|
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
#ifndef MODGMT_GSFUNCS_H |
||||||
|
#define MODGMT_GSFUNCS_H |
||||||
|
#include <string> |
||||||
|
#include <ghostscript/iapi.h> |
||||||
|
#include <ghostscript/ierrors.h> |
||||||
|
|
||||||
|
#ifndef e_Quit |
||||||
|
#define e_Quit (-101) |
||||||
|
#endif |
||||||
|
|
||||||
|
struct gs_abilities_struct |
||||||
|
{ |
||||||
|
bool havepngmono,havepngmonod,havepng16,havepng256,havepnggray,havepng16m; |
||||||
|
bool havejpeg,havejpeggray; |
||||||
|
bool havepdf,havebbox; |
||||||
|
}; |
||||||
|
|
||||||
|
extern struct gs_abilities_struct gs_abilities; |
||||||
|
|
||||||
|
struct gs_runtime |
||||||
|
{ |
||||||
|
union |
||||||
|
{ |
||||||
|
struct |
||||||
|
{ |
||||||
|
const std::string* in; |
||||||
|
uint pos; |
||||||
|
}; |
||||||
|
void* indata; |
||||||
|
}; |
||||||
|
std::string* out; |
||||||
|
std::string* err; |
||||||
|
}; |
||||||
|
|
||||||
|
typedef int (*gs_callback)(void *caller_handle, char *buf, int len); |
||||||
|
|
||||||
|
int GhostRun(const std::string& opts, const std::string& input, std::string* sout, std::string* serr, std::string* out); |
||||||
|
int GhostRun(const std::string& opts, gs_callback input, void* inputdata, std::string* sout, std::string* serr, std::string* out); |
||||||
|
|
||||||
|
void CheckGhostscriptAbilities(); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,135 @@ |
|||||||
|
#include <pthread.h> |
||||||
|
#include "common.h" |
||||||
|
#include "modgmt_internals.h" |
||||||
|
|
||||||
|
std::string header,footer; |
||||||
|
|
||||||
|
// Workaround exit() in GMT_Call_Module. May need because return mode of gmt api is not very reliable
|
||||||
|
#if defined MODGMT_WORKAROUND_EXIT |
||||||
|
const int GMTMODE=GMT_SESSION_NORMAL; |
||||||
|
#else |
||||||
|
const int GMTMODE=GMT_SESSION_NOEXIT; |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined MODGMT_WORKAROUND_EXIT |
||||||
|
// Exit handler.
|
||||||
|
static void gmtonexithandler(int ret, void* x) |
||||||
|
{ |
||||||
|
reinterpret_cast<struct gmtworkthreadpars*>(x)->ret=ret; |
||||||
|
close(reinterpret_cast<struct gmtworkthreadpars*>(x)->fd); |
||||||
|
pthread_exit(&(reinterpret_cast<struct gmtworkthreadpars*>(x)->ret)); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
// This function call GMT_Call_Module in separate thread. It just a hack to workaround absence of callbacks.
|
||||||
|
static void* gmtworkthread(void* x) |
||||||
|
{ |
||||||
|
struct gmtworkthreadpars* p=reinterpret_cast<struct gmtworkthreadpars*>(x); |
||||||
|
#if defined MODGMT_WORKAROUND_EXIT |
||||||
|
on_exit(gmtonexithandler,x); |
||||||
|
#endif |
||||||
|
GMT_Append_Option(p->api,GMT_Make_Option(p->api,'>',const_cast<char*>(("/dev/fd/"+std::to_string(p->fd)).c_str())),p->opts); |
||||||
|
p->ret=GMT_Call_Module(p->api,p->module,GMT_MODULE_OPT,p->opts); |
||||||
|
#if defined MODGMT_WORKAROUND_EXIT |
||||||
|
exit(p->ret); |
||||||
|
#endif |
||||||
|
close(p->fd); |
||||||
|
return &p->ret; |
||||||
|
} |
||||||
|
|
||||||
|
// Wrapper for GMT_Call_Module, res is output.
|
||||||
|
int callgmtmodule(void *api, const char *module, struct GMT_OPTION *opts, std::string* res, gmt_filter filt, void* filtpar) |
||||||
|
{ |
||||||
|
int pipefd[2]; |
||||||
|
pthread_t wthr; |
||||||
|
struct gmtworkthreadpars p; |
||||||
|
int *pret; |
||||||
|
int ret=0; |
||||||
|
|
||||||
|
if(0!=pipe(pipefd)) {ret=-1; goto end;} |
||||||
|
p.api=api; |
||||||
|
p.module=module; |
||||||
|
p.opts=opts; |
||||||
|
p.fd=pipefd[1]; |
||||||
|
|
||||||
|
pthread_create(&wthr,0,&gmtworkthread,&p); |
||||||
|
res->erase(); |
||||||
|
|
||||||
|
(*filt)(pipefd[0],res,filtpar); |
||||||
|
|
||||||
|
res->shrink_to_fit(); |
||||||
|
pthread_join(wthr,reinterpret_cast<void**>(&pret)); |
||||||
|
|
||||||
|
end: |
||||||
|
if(0!=ret) return ret; |
||||||
|
return *pret; |
||||||
|
} |
||||||
|
// Overloaded variant with opts as std::string
|
||||||
|
int callgmtmodule(void *api, const char *module, const std::string& opts, std::string* res, gmt_filter filt, void* filtpar) |
||||||
|
{ |
||||||
|
struct GMT_OPTION *gopts; |
||||||
|
int ret; |
||||||
|
gopts=str2options(api,opts); |
||||||
|
ret=callgmtmodule(api,module,gopts,res,filt,filtpar); |
||||||
|
GMT_Destroy_Options(api,&gopts); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
// Overloaded variant with opts as char*
|
||||||
|
int callgmtmodule(void *api, const char *module, const char* opts, std::string* res, gmt_filter filt, void* filtpar) |
||||||
|
{ |
||||||
|
struct GMT_OPTION *gopts; |
||||||
|
int ret; |
||||||
|
gopts=str2options(api,opts); |
||||||
|
ret=callgmtmodule(api,module,gopts,res,filt,filtpar); |
||||||
|
GMT_Destroy_Options(api,&gopts); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
// Calculate real width and height of projection. If height!=0 recalculate width accordingly.
|
||||||
|
bool ProjectionRealSize(struct gmt_projection& p, double height) |
||||||
|
{ |
||||||
|
// Decart projection is special case
|
||||||
|
if(gmt_projection::XY==p.proj) |
||||||
|
{ |
||||||
|
p.rwidth=p.width; |
||||||
|
p.rheight=p.x.height; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void* gmtapi; |
||||||
|
int ret=0; |
||||||
|
std::string wh; |
||||||
|
double w,h; |
||||||
|
double sw=p.width; |
||||||
|
WordList wl; |
||||||
|
WordList::const_iterator cw; |
||||||
|
|
||||||
|
gmtapi=GMT_Create_Session("ProjectionRealSize",2,GMTMODE,0); |
||||||
|
if(0==gmtapi) return false; |
||||||
|
p.width=1.0; |
||||||
|
ret=callgmtmodule(gmtapi,"mapproject",p.Value()+" -W",&wh); |
||||||
|
p.width=sw; |
||||||
|
GMT_Destroy_Session(gmtapi); |
||||||
|
if(0!=ret) return false; |
||||||
|
|
||||||
|
wl=Split(wh," \t\n"); |
||||||
|
if(2!=wl.size()) return false; |
||||||
|
cw=wl.begin(); |
||||||
|
if(!str2double(*cw,&w)) return false; |
||||||
|
cw++; |
||||||
|
if(!str2double(*cw,&h)) return false; |
||||||
|
if(height>0.0) |
||||||
|
{ |
||||||
|
p.width=height/h; |
||||||
|
p.rwidth=w*height/h; |
||||||
|
p.rheight=height; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
p.width=sw/w; |
||||||
|
p.rwidth=sw; |
||||||
|
p.rheight=h*sw/w; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
#ifndef MODGMT_INTERNALS_H |
||||||
|
#define MODGMT_INTERNALS_H |
||||||
|
#include <gmt.h> |
||||||
|
#include <string.h> |
||||||
|
#include "modgmt_filters.h" |
||||||
|
#include "modgmt_structs.h" |
||||||
|
|
||||||
|
// here we save header and footer of gmt-produced eps files
|
||||||
|
extern std::string header,footer; |
||||||
|
extern const int GMTMODE; |
||||||
|
|
||||||
|
// Parameters for working thread
|
||||||
|
struct gmtworkthreadpars |
||||||
|
{ |
||||||
|
void* api; |
||||||
|
const char* module; |
||||||
|
struct GMT_OPTION* opts; |
||||||
|
int fd; |
||||||
|
int ret; |
||||||
|
}; |
||||||
|
|
||||||
|
// Calling GMT module with filtering
|
||||||
|
int callgmtmodule(void *api, const char *module, struct GMT_OPTION *opts, std::string* res, gmt_filter filt=gmt_filter_default, void* filtpar=0); |
||||||
|
int callgmtmodule(void *api, const char *module, const std::string& opts, std::string* res, gmt_filter filt=gmt_filter_default, void* filtpar=0); |
||||||
|
int callgmtmodule(void *api, const char *module, const char* opts, std::string* res, gmt_filter filt=gmt_filter_default, void* filtpar=0); |
||||||
|
|
||||||
|
// Workaround non-const pointer in GMT_Create_Options
|
||||||
|
inline struct GMT_OPTION* str2options(void *api, const char* str, size_t size=0) |
||||||
|
{ |
||||||
|
static char default_gmt_options[]="--GMT_HISTORY=f --PS_LINE_CAP=round --PS_LINE_JOIN=round --GMT_COMPATIBILITY=5 --PS_PAGE_ORIENTATION=portrait --PS_IMAGE_COMPRESS=deflate,9 --PROJ_LENGTH_UNIT=cm"; |
||||||
|
char* t; |
||||||
|
if(0==size) t=strdup(str); |
||||||
|
else |
||||||
|
{ |
||||||
|
t=static_cast<char*>(malloc(size+1)); |
||||||
|
memcpy(t,str,size); |
||||||
|
t[size]=0; |
||||||
|
} |
||||||
|
struct GMT_OPTION* opts=GMT_Create_Options(api,0,t); |
||||||
|
GMT_Append_Option(api,GMT_Create_Options(api,0,default_gmt_options),opts); |
||||||
|
free(t); |
||||||
|
return opts; |
||||||
|
} |
||||||
|
inline struct GMT_OPTION* str2options(void *api, const std::string& str) |
||||||
|
{ |
||||||
|
return str2options(api,str.data(),str.length()); |
||||||
|
} |
||||||
|
|
||||||
|
// Calculate real width and height of projection. If height!=0 recalculate width accordingly.
|
||||||
|
bool ProjectionRealSize(struct gmt_projection& p, double height=0.0); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,460 @@ |
|||||||
|
#include <regex> |
||||||
|
#include <stack> |
||||||
|
#include "modgmt_map.h" |
||||||
|
#include "modgmt_func.h" |
||||||
|
#include "modgmt_gsfuncs.h" |
||||||
|
|
||||||
|
struct input_runtime |
||||||
|
{ |
||||||
|
std::list<std::shared_ptr<std::string> >::const_iterator ci,end; |
||||||
|
size_t pos; |
||||||
|
}; |
||||||
|
|
||||||
|
static int gs_bbox_callback(void *caller_handle, char *buf, int len) |
||||||
|
{ |
||||||
|
struct input_runtime* r=static_cast<struct input_runtime*>(static_cast<struct gs_runtime*>(caller_handle)->indata); |
||||||
|
size_t buflen=static_cast<size_t>(len); |
||||||
|
size_t inbuf=0; |
||||||
|
|
||||||
|
if(r->ci==r->end) return 0; |
||||||
|
while(inbuf!=buflen) |
||||||
|
{ |
||||||
|
if((*r->ci)->length()-r->pos>=buflen-inbuf) // Remainder of string greater or equal remainder of buffer
|
||||||
|
{ |
||||||
|
// Just copy part of string to buffer
|
||||||
|
memcpy(buf+inbuf,(*r->ci)->c_str()+r->pos,buflen-inbuf); |
||||||
|
r->pos+=buflen-inbuf; |
||||||
|
inbuf=buflen; |
||||||
|
} |
||||||
|
else // Remainder of string lesser then remainder of buffer
|
||||||
|
{ |
||||||
|
// Copy remainder of string to buffer
|
||||||
|
memcpy(buf+inbuf,(*r->ci)->c_str()+r->pos,(*r->ci)->length()-r->pos); |
||||||
|
inbuf+=(*r->ci)->length()-r->pos; |
||||||
|
// Go to next string
|
||||||
|
r->ci++; r->pos=0; |
||||||
|
if(r->ci==r->end) break; // No more strings, leave.
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return inbuf; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static inline int eps2pdf(const std::string& eps, std::string* pdf, double res, uint ta=4, uint ga=4) |
||||||
|
{ |
||||||
|
if(!gs_abilities.havepdf) return 1; // No pdf support
|
||||||
|
return GhostRun("-r"+ToString(res)+" -dEPSCrop -dTextAlphaBits="+ToString(ta)+" -dGraphicAlphaBits="+ToString(ga)+" -dNOPLATFONT -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode -dAutoFilterGrayImages=false -dGrayImageFilter=/FlateEncode -dAutoFilterMonoImages=false -dMonoImageFilter=/CCITTFaxEncode -sDEVICE=pdfwrite -dMaxInlineImageSize=0 -c .setpdfwrite <</NeverEmbed [ ]>> setdistillerparams",eps,0,0,pdf); |
||||||
|
} |
||||||
|
|
||||||
|
// Creating eps map from sequence of layers
|
||||||
|
/*
|
||||||
|
Input: |
||||||
|
If first argument is a string, then this string is a title of map (%%Title parameter in eps file). |
||||||
|
Other arguments are sequence of pairs and layers. |
||||||
|
Pairs can be x, y, xr, yr, xg, yg, xgr, ygr. |
||||||
|
x and y set shift for next layer in cm. This local shift overrides global (setted by xg, yg). |
||||||
|
xr and yr do the same but respect to global shift. |
||||||
|
xg and yg set global shift (for all subsequent layers). |
||||||
|
xgr and ygr add corresponding values to global shift. |
||||||
|
Resulted shift is added to own shift of layer (setted by function LayerShift). |
||||||
|
*/ |
||||||
|
const ObjectBase* GMT_Map(const ObjectList* input) |
||||||
|
{ |
||||||
|
std::string err; |
||||||
|
std::string title; |
||||||
|
|
||||||
|
double xg,yg,x,y; |
||||||
|
bool xislocal=false, yislocal=false; |
||||||
|
std::list<std::shared_ptr<std::string> > data; |
||||||
|
|
||||||
|
xg=yg=x=y=0.0; |
||||||
|
|
||||||
|
// FIXME: Workaround ghostscript bug 202735
|
||||||
|
// See http://bugs.ghostscript.com/show_bug.cgi?id=202735
|
||||||
|
data.emplace_back(new std::string("4000 4000 translate")); |
||||||
|
data.emplace_back(new std::string(header)); |
||||||
|
for(auto i=input->begin(); i!=input->end(); ++i) |
||||||
|
{ |
||||||
|
// Check if first argument is string
|
||||||
|
if(input->begin()==i) |
||||||
|
{ |
||||||
|
OBType<ObjectString> s(*i); |
||||||
|
if(s) |
||||||
|
{ |
||||||
|
title=s->Value(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Check if argument is pair
|
||||||
|
{ |
||||||
|
OBType<ObjectPair> p(*i); |
||||||
|
if(p) |
||||||
|
{ |
||||||
|
std::string name=p->Name(); |
||||||
|
tolower(name); |
||||||
|
Base2Double d; |
||||||
|
bool suc=true; |
||||||
|
double val=d.Convert(p->Value(),&suc,err); |
||||||
|
if(!suc) goto fail; // Conversion failed
|
||||||
|
suc=false; |
||||||
|
if("x"==name) {suc=true; xislocal=true; x=val;} |
||||||
|
if("y"==name) {suc=true; yislocal=true; y=val;} |
||||||
|
if("xr"==name) {suc=true; xislocal=true; x=val+xg;} |
||||||
|
if("yr"==name) {suc=true; yislocal=true; y=val+yg;} |
||||||
|
if("xg"==name) {suc=true; xg=val;} |
||||||
|
if("yg"==name) {suc=true; yg=val;} |
||||||
|
if("xgr"==name) {suc=true; xg+=val;} |
||||||
|
if("ygr"==name) {suc=true; yg+=val;} |
||||||
|
if(!suc) {err="Unknown parameter name: "+p->Name(); goto fail;} // Unknown name
|
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Check if argument is layer
|
||||||
|
{ |
||||||
|
OBType<ObjectGMTLayer> l(*i); |
||||||
|
if(l) |
||||||
|
{ |
||||||
|
struct gmt_layer layer=l->Data(); |
||||||
|
layer.shiftx+=(xislocal?x:xg); |
||||||
|
layer.shifty+=(yislocal?y:yg); |
||||||
|
xislocal=yislocal=false; |
||||||
|
if(layer.Shifted()) |
||||||
|
{ |
||||||
|
data.emplace_back(new std::string(layer.BeginShift())); |
||||||
|
data.emplace_back(layer.data); |
||||||
|
data.emplace_back(new std::string(layer.EndShift())); |
||||||
|
} |
||||||
|
else data.emplace_back(layer.data); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
err="Unknown argument type: "+i->Type(); |
||||||
|
goto fail; // Unknown type of argument
|
||||||
|
} |
||||||
|
data.emplace_back(new std::string(footer)); |
||||||
|
|
||||||
|
// Calculate bounding box
|
||||||
|
int64_t bblx,bbly,bbrx,bbry; |
||||||
|
{ |
||||||
|
std::string bboxes; |
||||||
|
struct input_runtime in={data.begin(),data.end(),0}; |
||||||
|
int ret; |
||||||
|
|
||||||
|
ret=GhostRun("-sDEVICE=bbox",gs_bbox_callback,&in,0,&bboxes,0); // Bounding box is writed on stderr
|
||||||
|
if(0!=ret) {err="Can't determine BoundingBox"; goto fail;} // Something wrong
|
||||||
|
|
||||||
|
std::smatch m; |
||||||
|
std::smatch::const_iterator ci; |
||||||
|
std::regex r("%%BoundingBox:[[:space:]]+(-?[0-9]+)[[:space:]]+(-?[0-9]+)[[:space:]]+(-?[0-9]+)[[:space:]]+(-?[0-9]+)"); |
||||||
|
bool ok=true; |
||||||
|
|
||||||
|
std::regex_search(bboxes,m,r); |
||||||
|
if(5!=m.size()) {err="Something go wrong, this is strange and scary"; goto fail; }// This is strange and scary
|
||||||
|
ci=m.cbegin(); |
||||||
|
ci++; // Skip full match
|
||||||
|
|
||||||
|
ok=ok && str2int(*ci++,&bblx); |
||||||
|
ok=ok && str2int(*ci++,&bbly); |
||||||
|
ok=ok && str2int(*ci++,&bbrx); |
||||||
|
ok=ok && str2int(*ci++,&bbry); |
||||||
|
if(!ok) {err="Unexpected error!"; goto fail;} // Unexpected!
|
||||||
|
// FIXME: Workaround ghostscript bug 202735
|
||||||
|
// We add 5 points to each margin because ghostscript does'nt count linewidths when calculate bounding box
|
||||||
|
bblx-=4005; |
||||||
|
bbly-=4005; |
||||||
|
bbrx-=3995; |
||||||
|
bbry-=3995; |
||||||
|
} |
||||||
|
data.pop_front(); |
||||||
|
|
||||||
|
// Creating eps file
|
||||||
|
{ |
||||||
|
std::string curtime; |
||||||
|
{ |
||||||
|
const size_t bufsize=1024; |
||||||
|
char buf[bufsize]; |
||||||
|
time_t sec; |
||||||
|
struct tm t; |
||||||
|
|
||||||
|
sec=time(0); |
||||||
|
localtime_r(&sec,&t); |
||||||
|
curtime.assign(buf, strftime(buf,bufsize,"%F %T %Z",&t)); |
||||||
|
} |
||||||
|
std::string* eps=new std::string("%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: "); |
||||||
|
*eps+=ToString(bblx)+" "+ToString(bbly)+" "+ToString(bbrx)+" "+ToString(bbry); |
||||||
|
*eps+="\n%%Title: "+(title.empty()?std::string("untitled"):title); |
||||||
|
*eps+="\n%%Creator: gmt_makemap\n%%CreationDate: "+curtime; |
||||||
|
*eps+="\n%%LanguageLevel: 2\n%%Orientation: Portrait\n%%EndComments\n"; |
||||||
|
for(auto d: data) *eps+=*d; |
||||||
|
return new ObjectGMTMap(eps,bblx,bbly,bbrx,bbry); |
||||||
|
} |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("Map",err); |
||||||
|
} |
||||||
|
|
||||||
|
// Creating pdf from eps
|
||||||
|
/*
|
||||||
|
Input: |
||||||
|
One argument must be GMTMap. |
||||||
|
Optionally, resolution can be specified by pair with name resolution, res or r and double value. Default is 720. |
||||||
|
*/ |
||||||
|
const ObjectBase* GMT_Convert2PDF(const ObjectList* input) |
||||||
|
{ |
||||||
|
std::string err; |
||||||
|
RNFPar<SearchGMTMap,ObjectGMTMap> map("map"); |
||||||
|
ONPar<Base2PosD> r("resolution",720); |
||||||
|
ParseNamedParameters params(input,map,r); |
||||||
|
const ObjectGMTMap* m=map; |
||||||
|
|
||||||
|
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support
|
||||||
|
if(!params) {err=params.Error(); goto fail;} // Parsing error
|
||||||
|
|
||||||
|
{ |
||||||
|
std::string* out=new std::string; |
||||||
|
int ret=eps2pdf(*(m->pValue()),out,r); |
||||||
|
if(0!=ret) {err="Conversion of EPS to PDF failed"; delete out; goto fail; } // Something wrong
|
||||||
|
return new ObjectGMTMapPDF(out,m->Bblx(),m->Bbly(),m->Bbrx(),m->Bbry()); |
||||||
|
} |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("EPS2PDF",err); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Creating png from eps or pdf
|
||||||
|
/*
|
||||||
|
Input: |
||||||
|
One argument must be GMTMap or GMTMapPDF. |
||||||
|
Other parameter are optional name-value pairs. |
||||||
|
resolution, res or r - output resolution (pixels/inch). Default: 300. |
||||||
|
Instead of resolution, width (width or w) or height (height or h) in pixels may be specified. Resolution, width and height are mutually exclusive. Large value of resolution may result in ghostscript error. |
||||||
|
colorspace, cspace or cs - is a string, one of "mono" or "monochrome" (black and white image), "monodiffused" or "monod" (black and white image made from grayscale by error diffusion), "16c" or "16" (16 colors), "256c" or "256" (256 colors), "gray", "grey" or "g" (256 shades of gray), "full", "8bit" or "color" (8-bit per component rgb). Some of these values may return error, this depends on ghostscript setup in system. Default: "color". |
||||||
|
For colorspaces "monod", "color" and "gray" may be also specified parameter downscale (dscale or ds) with small integer value (from 1 to 10). The image initially rendered in dscale*res resolution and downscaling to res resolution. This increase output quality (lines and contours are more "soft"), but may result in ghostscript error if rendering resolution is too high. |
||||||
|
textantialiasing or taa - is a string, can be "none" ("no"), "small" ("s") or "full" ("f"). Controls text antialiasing. Default: "full". |
||||||
|
graphicsantialiasing or gaa - is a string, can be "none", "small" or "full". Controls graphics antialiasing. Default: "full". |
||||||
|
antialiasing or aa - can be used to set graphics and text antialiasing simultaneously. |
||||||
|
*/ |
||||||
|
const ObjectBase* GMT_Convert2PNG(const ObjectList* input) |
||||||
|
{ |
||||||
|
std::string gsdev,err; |
||||||
|
double res; |
||||||
|
|
||||||
|
ONPar<Base2PosD> r("resolution",300),ds("d[own]scale",1.0); |
||||||
|
ONPar<Base2Pos> w("width"),h("height"); |
||||||
|
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full"); |
||||||
|
const ObjectGMTMap* me; |
||||||
|
const ObjectGMTMapPDF* mp; |
||||||
|
const GMTMap* m; |
||||||
|
uint aat,aag; |
||||||
|
uint dscale; |
||||||
|
|
||||||
|
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no png
|
||||||
|
// Search map
|
||||||
|
{ |
||||||
|
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map"); |
||||||
|
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map"); |
||||||
|
ParseNamedParameters peps(input,mapeps); |
||||||
|
ParseNamedParameters ppdf(input,mappdf); |
||||||
|
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;} |
||||||
|
me=mapeps; mp=mappdf; |
||||||
|
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened
|
||||||
|
if(nullptr!=me) m=me; else m=mp; |
||||||
|
} |
||||||
|
// Parse other parameters
|
||||||
|
{ |
||||||
|
ParseNamedParameters params(input,r,ds,w,h,cs,taa,gaa,aa); |
||||||
|
if(!params) {err=params.Error(); goto fail;} |
||||||
|
} |
||||||
|
|
||||||
|
// Determine resolution
|
||||||
|
{ |
||||||
|
// Check existence
|
||||||
|
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed
|
||||||
|
if(r.Exist()) res=r; |
||||||
|
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx()); |
||||||
|
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly()); |
||||||
|
} |
||||||
|
|
||||||
|
// Color model
|
||||||
|
{ |
||||||
|
std::string cspace=cs; |
||||||
|
tolower(cspace); |
||||||
|
if(("mono" ==cspace || "monochrome" ==cspace ) && gs_abilities.havepngmono) gsdev="pngmono"; |
||||||
|
if(("monod"==cspace || "monodiffused"==cspace ) && gs_abilities.havepngmonod) gsdev="pngmonod"; |
||||||
|
if(("16c" ==cspace || "16" ==cspace ) && gs_abilities.havepng16) gsdev="png16"; |
||||||
|
if(("256c" ==cspace || "256" ==cspace ) && gs_abilities.havepng256) gsdev="png256"; |
||||||
|
if(("gray" ==cspace || "grey" ==cspace || "g" ==cspace) && gs_abilities.havepnggray) gsdev="pnggray"; |
||||||
|
if(("full" ==cspace || "8bit" ==cspace || "color"==cspace) && gs_abilities.havepng16m) gsdev="png16m"; |
||||||
|
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value
|
||||||
|
} |
||||||
|
|
||||||
|
// Antialiasing
|
||||||
|
{ |
||||||
|
std::string aags=aa,aats=aa; |
||||||
|
if(taa.Exist()) aats=taa; |
||||||
|
if(gaa.Exist()) aags=gaa; |
||||||
|
tolower(aags); tolower(aats); |
||||||
|
|
||||||
|
if("none" ==aags || "no"==aags || "n"==aags) aag=1; |
||||||
|
if("none" ==aats || "no"==aats || "n"==aats) aat=1; |
||||||
|
|
||||||
|
if("small"==aags || "s" ==aags ) aag=2; |
||||||
|
if("small"==aats || "s" ==aats ) aat=2; |
||||||
|
|
||||||
|
if("full" ==aags || "f" ==aags ) aag=4; |
||||||
|
if("full" ==aats || "f" ==aats ) aat=4; |
||||||
|
|
||||||
|
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;} |
||||||
|
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;} |
||||||
|
} |
||||||
|
|
||||||
|
// Downscale
|
||||||
|
if("pngmonod"==gsdev || "pnggray"==gsdev || "png16m"==gsdev) |
||||||
|
{ |
||||||
|
dscale=static_cast<uint>(ds); |
||||||
|
if(dscale<1 || dscale>10) {err="Downscale must be in interval from 1 to 10"; goto fail;} |
||||||
|
res*=dscale; |
||||||
|
} |
||||||
|
|
||||||
|
// Go!
|
||||||
|
{ |
||||||
|
std::string* pdf=0; |
||||||
|
int ret; |
||||||
|
if(nullptr!=me) |
||||||
|
{ |
||||||
|
pdf=new std::string; |
||||||
|
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag); |
||||||
|
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong
|
||||||
|
} |
||||||
|
|
||||||
|
{ |
||||||
|
std::string* out=new std::string; |
||||||
|
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+((dscale>1)?(" -dDownScaleFactor="+ToString(dscale)):""),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out); |
||||||
|
if(0!=pdf) delete pdf; |
||||||
|
if(0!=ret) {err="Can't convert PDF to PNG"; delete out; goto fail; } // Something wrong
|
||||||
|
return new ObjectGMTImage(out); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("EPS2PNG",err); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Creating jpeg from eps or pdf
|
||||||
|
/*
|
||||||
|
Input: |
||||||
|
One argument must be GMTMap or GMTMapPDF. |
||||||
|
Other parameter are optional name-value pairs. |
||||||
|
resolution, res or r - output resolution (pixels/inch). Default: 300. |
||||||
|
Instead of resolution, width (width or w) or height (height or h) in pixels may be specified. Resolution, width and height are mutually exclusive. Large value of resolution may result in ghostscript error. |
||||||
|
colorspace, cspace or cs - is a string, one "gray", "grey" or "g" (256 shades of gray), "full", "8bit" or "color" (8-bit per component rgb). Some of these values may return error, this depends on ghostscript setup in system. Default: "color". |
||||||
|
quality, qual or q - JPEG quality level, integer from 0 to 100. Default: 75. |
||||||
|
textantialiasing or taa - is a string, can be "none" ("no"), "small" ("s") or "full" ("f"). Controls text antialiasing. Default: "full". |
||||||
|
graphicsantialiasing or gaa - is a string, can be "none", "small" or "full". Controls graphics antialiasing. Default: "full". |
||||||
|
antialiasing or aa - can be used to set graphics and text antialiasing simultaneously. |
||||||
|
*/ |
||||||
|
const ObjectBase* GMT_Convert2JPG(const ObjectList* input) |
||||||
|
{ |
||||||
|
std::string gsdev,err; |
||||||
|
|
||||||
|
ONPar<Base2PosD> r("resolution",300); |
||||||
|
ONPar<Base2Pos> w("width"),h("height"); |
||||||
|
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full"); |
||||||
|
ONPar<Base2NonNegD> q("quality",75); |
||||||
|
const ObjectGMTMap* me; |
||||||
|
const ObjectGMTMapPDF* mp; |
||||||
|
const GMTMap* m; |
||||||
|
double res; |
||||||
|
uint aat,aag; |
||||||
|
uint qual; |
||||||
|
|
||||||
|
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no jpeg
|
||||||
|
// Search map
|
||||||
|
{ |
||||||
|
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map"); |
||||||
|
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map"); |
||||||
|
ParseNamedParameters peps(input,mapeps); |
||||||
|
ParseNamedParameters ppdf(input,mappdf); |
||||||
|
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;} |
||||||
|
me=mapeps; mp=mappdf; |
||||||
|
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened
|
||||||
|
if(nullptr!=me) m=me; else m=mp; |
||||||
|
} |
||||||
|
// Parse other parameters
|
||||||
|
{ |
||||||
|
ParseNamedParameters params(input,r,q,w,h,cs,taa,gaa,aa); |
||||||
|
if(!params) {err=params.Error(); goto fail;} |
||||||
|
} |
||||||
|
|
||||||
|
// Determine resolution
|
||||||
|
{ |
||||||
|
// Check existence
|
||||||
|
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed
|
||||||
|
if(r.Exist()) res=r; |
||||||
|
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx()); |
||||||
|
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly()); |
||||||
|
} |
||||||
|
|
||||||
|
// Color model
|
||||||
|
{ |
||||||
|
std::string cspace=cs; |
||||||
|
tolower(cspace); |
||||||
|
if(("gray"==cspace || "grey"==cspace || "g" ==cspace) && gs_abilities.havejpeggray) gsdev="jpeggray"; |
||||||
|
if(("full"==cspace || "8bit"==cspace || "color"==cspace) && gs_abilities.havejpeg) gsdev="jpeg"; |
||||||
|
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value
|
||||||
|
} |
||||||
|
|
||||||
|
// Antialiasing
|
||||||
|
{ |
||||||
|
std::string aags=aa,aats=aa; |
||||||
|
if(taa.Exist()) aats=taa; |
||||||
|
if(gaa.Exist()) aags=gaa; |
||||||
|
tolower(aags); tolower(aats); |
||||||
|
|
||||||
|
if("none" ==aags || "no"==aags || "n"==aags) aag=1; |
||||||
|
if("none" ==aats || "no"==aats || "n"==aats) aat=1; |
||||||
|
|
||||||
|
if("small"==aags || "s" ==aags ) aag=2; |
||||||
|
if("small"==aats || "s" ==aats ) aat=2; |
||||||
|
|
||||||
|
if("full" ==aags || "f" ==aags ) aag=4;
|
||||||
|
if("full" ==aats || "f" ==aats ) aat=4; |
||||||
|
|
||||||
|
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;} |
||||||
|
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;} |
||||||
|
} |
||||||
|
|
||||||
|
// Quality
|
||||||
|
{ |
||||||
|
qual=static_cast<uint>(q); |
||||||
|
if(q>100) {err="JPEG quality must not exceed 100"; goto fail;} // Error
|
||||||
|
} |
||||||
|
|
||||||
|
// Go!
|
||||||
|
{ |
||||||
|
std::string* pdf=0; |
||||||
|
int ret; |
||||||
|
if(nullptr!=me) |
||||||
|
{ |
||||||
|
pdf=new std::string; |
||||||
|
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag); |
||||||
|
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong
|
||||||
|
} |
||||||
|
|
||||||
|
{ |
||||||
|
std::string* out=new std::string; |
||||||
|
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+" -dJPEGQ="+ToString(qual),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out); |
||||||
|
if(0!=pdf) delete pdf; |
||||||
|
if(0!=ret) {err="Can't convert PDF to JPEG"; delete out; goto fail; } // Something wrong
|
||||||
|
return new ObjectGMTImage(out); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fail: |
||||||
|
return new ObjectError("EPS2JPEG",err); |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
#ifndef MODGMT_MAP_H |
||||||
|
#define MODGMT_MAP_H |
||||||
|
#include <cmath> |
||||||
|
#include "common.h" |
||||||
|
|
||||||
|
class GMTBlob: public ObjectBase |
||||||
|
{ |
||||||
|
GMTBlob()=delete; |
||||||
|
protected: |
||||||
|
std::shared_ptr<std::string> data; |
||||||
|
GMTBlob(const GMTBlob& b)=default; |
||||||
|
GMTBlob(GMTBlob&& b)=default; |
||||||
|
GMTBlob(const GMTBlob* p):data(p->data) {} |
||||||
|
GMTBlob(std::string* s):data(s) {} |
||||||
|
|
||||||
|
public: |
||||||
|
// Pure virtual overrides
|
||||||
|
bool Print() const override |
||||||
|
{ |
||||||
|
COUT(NORMAL)<<std::endl<<"Object type: "<<Type()<<std::endl; |
||||||
|
return true; |
||||||
|
} |
||||||
|
const int8_t* Blob(size_t* size) const override |
||||||
|
{ |
||||||
|
*size=data->size(); |
||||||
|
return reinterpret_cast<const int8_t*>(data->data()); |
||||||
|
} |
||||||
|
// Data access
|
||||||
|
const std::string* pValue() const {return data.get();} |
||||||
|
}; |
||||||
|
|
||||||
|
class GMTMap: public GMTBlob |
||||||
|
{ |
||||||
|
protected: |
||||||
|
int32_t bblx,bbly,bbrx,bbry; |
||||||
|
GMTMap(const GMTMap* p):GMTBlob(p),bblx(p->bblx),bbly(p->bbly),bbrx(p->bbrx),bbry(p->bbry) {}; |
||||||
|
GMTMap(std::string* s, int nbblx, int nbbly, int nbbrx, int nbbry):GMTBlob(s),bblx(nbblx),bbly(nbbly),bbrx(nbbrx),bbry(nbbry) {}; |
||||||
|
public: |
||||||
|
int32_t Bblx() const {return bblx;} |
||||||
|
int32_t Bbly() const {return bbly;} |
||||||
|
int32_t Bbrx() const {return bbrx;} |
||||||
|
int32_t Bbry() const {return bbry;} |
||||||
|
}; |
||||||
|
|
||||||
|
class ObjectGMTMapPDF: public GMTMap |
||||||
|
{ |
||||||
|
ObjectGMTMapPDF(const ObjectGMTMapPDF* p):GMTMap(p) {}; |
||||||
|
public: |
||||||
|
ObjectGMTMapPDF(std::string* s, int nbblx, int nbbly, int nbbrx, int nbbry):GMTMap(s,nbblx,nbbly,nbbrx,nbbry) {}; |
||||||
|
// Pure virtual overrides
|
||||||
|
ObjectBase* Copy() const override {return new ObjectGMTMapPDF(this);} |
||||||
|
std::string Type() const override {return "GMTMapPDF";} |
||||||
|
}; |
||||||
|
|
||||||
|
class ObjectGMTMap: public GMTMap |
||||||
|
{ |
||||||
|
ObjectGMTMap(const ObjectGMTMap* p):GMTMap(p) {}; |
||||||
|
public: |
||||||
|
ObjectGMTMap(std::string* s, int nbblx, int nbbly, int nbbrx, int nbbry):GMTMap(s,nbblx,nbbly,nbbrx,nbbry) {}; |
||||||
|
// Pure virtual overrides
|
||||||
|
ObjectBase* Copy() const override {return new ObjectGMTMap(this);} |
||||||
|
std::string Type() const override {return "GMTMap";} |
||||||
|
}; |
||||||
|
|
||||||
|
class ObjectGMTImage: public GMTBlob |
||||||
|
{ |
||||||
|
ObjectGMTImage(const ObjectGMTImage* p):GMTBlob(p) {}; |
||||||
|
public: |
||||||
|
ObjectGMTImage(std::string* s):GMTBlob(s) {}; |
||||||
|
// Pure virtual overrides
|
||||||
|
ObjectBase* Copy() const override {return new ObjectGMTImage(this);} |
||||||
|
std::string Type() const override {return "GMTImage";} |
||||||
|
}; |
||||||
|
|
||||||
|
// Convertor to search object
|
||||||
|
template<class Object> |
||||||
|
class SearchObject |
||||||
|
{ |
||||||
|
public: |
||||||
|
using ValueType=const Object*; |
||||||
|
template<class... Args> |
||||||
|
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err, Args... args) |
||||||
|
{ |
||||||
|
OBType<Object> gp(ob); |
||||||
|
switch(gp.Error()) |
||||||
|
{ |
||||||
|
case(OBTypeErr::OK): return gp; |
||||||
|
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;} |
||||||
|
case(OBTypeErr::TYPEMISMATCH): {err=ob->Type()+" is not correct: type mismatch"; break;} |
||||||
|
} |
||||||
|
*res=false; |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
}; |
||||||
|
// Convertor to search GMTMap objects
|
||||||
|
using SearchGMTMap=SearchObject<ObjectGMTMap>; |
||||||
|
using SearchGMTMapPDF=SearchObject<ObjectGMTMapPDF>; |
||||||
|
|
||||||
|
// Creating eps map from set of layers
|
||||||
|
const ObjectBase* GMT_Map(const ObjectList* input); |
||||||
|
|
||||||
|
// Converting map to pdf
|
||||||
|
const ObjectBase* GMT_Convert2PDF(const ObjectList* input); |
||||||
|
|
||||||
|
// Converting map to png
|
||||||
|
const ObjectBase* GMT_Convert2PNG(const ObjectList* input); |
||||||
|
|
||||||
|
// Converting map to jpeg
|
||||||
|
const ObjectBase* GMT_Convert2JPG(const ObjectList* input); |
||||||
|
|
||||||
|
#endif |
||||||
|
|
@ -0,0 +1,97 @@ |
|||||||
|
#include "modgmt_objects.h" |
||||||
|
|
||||||
|
template<> const std::string ObjectGMTCoord::type="GMTCoord"; |
||||||
|
template<> const std::string ObjectGMTRegion::type="GMTRegion"; |
||||||
|
template<> const std::string ObjectGMTProjection::type="GMTProjection"; |
||||||
|
template<> const std::string ObjectGMTColor::type="GMTColor"; |
||||||
|
template<> const std::string ObjectGMTDash::type="GMTDash"; |
||||||
|
template<> const std::string ObjectGMTPen::type="GMTPen"; |
||||||
|
template<> const std::string ObjectGMTFont::type="GMTFont"; |
||||||
|
template<> const std::string ObjectGMTLayer::type="GMTLayer"; |
||||||
|
|
||||||
|
template<> const int8_t* ObjectGMTLayer::Blob(size_t* size) const |
||||||
|
{ |
||||||
|
if(s.Shifted()) |
||||||
|
{ |
||||||
|
std::string b=s.BeginShift(); |
||||||
|
std::string e=s.EndShift(); |
||||||
|
int8_t* p=new int8_t[b.size()+s.data->size()+e.size()]; |
||||||
|
memcpy(p,b.data(),b.size()); |
||||||
|
memcpy(p+b.size(),s.data->data(),s.data->size()); |
||||||
|
memcpy(p+b.size()+s.data->size(),e.data(),e.size()); |
||||||
|
return p; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
*size=s.data->size(); |
||||||
|
return reinterpret_cast<const int8_t*>(s.data->data()); |
||||||
|
} |
||||||
|
} |
||||||
|
template<> void ObjectGMTLayer::DeallocBlob(const int8_t* ptr) const |
||||||
|
{ |
||||||
|
if(s.Shifted()) delete[] ptr; |
||||||
|
} |
||||||
|
|
||||||
|
std::map<std::string,gmt_projection::projection> gmt_projection::projnames; |
||||||
|
|
||||||
|
void gmt_projection::FillProjNames() |
||||||
|
{ |
||||||
|
projnames["(xy|decart)"]=XY; |
||||||
|
projnames["c[ylindrical][( |_)]equidistant"]=CYL_EQU; |
||||||
|
projnames["mercator"]=MERCATOR; |
||||||
|
projnames["t[ransverse][( |_)]mercator"]=TRANSMERCATOR; |
||||||
|
projnames["o[blique][( |_)]mercator"]=OBLIQMERCATOR; |
||||||
|
projnames["cassini"]=CASSINI; |
||||||
|
projnames["c[ylindrical][( |_)]eq[ua(l|l-)]area"]=CYL_EQA; |
||||||
|
projnames["[c[ylindrical][( |_)]]miller"]=MILLER; |
||||||
|
projnames["c[ylindrical][( |_)]stereographic"]=CYL_STERE; |
||||||
|
} |
||||||
|
|
||||||
|
bool gmt_font::FillFontNames() |
||||||
|
{ |
||||||
|
families.insert("Helvetica"); |
||||||
|
families.insert("Helvetica-Bold"); |
||||||
|
families.insert("Helvetica-Oblique"); |
||||||
|
families.insert("Helvetica-BoldOblique"); |
||||||
|
families.insert("Times-Roman"); |
||||||
|
families.insert("Times-Bold"); |
||||||
|
families.insert("Times-Italic"); |
||||||
|
families.insert("Times-BoldItalic"); |
||||||
|
families.insert("Courier"); |
||||||
|
families.insert("Courier-Bold"); |
||||||
|
families.insert("Courier-Oblique"); |
||||||
|
families.insert("Courier-BoldOblique"); |
||||||
|
families.insert("Symbol"); |
||||||
|
families.insert("AvantGarde-Book"); |
||||||
|
families.insert("AvantGarde-BookOblique"); |
||||||
|
families.insert("AvantGarde-Demi"); |
||||||
|
families.insert("AvantGarde-DemiOblique"); |
||||||
|
families.insert("Bookman-Demi"); |
||||||
|
families.insert("Bookman-DemiItalic"); |
||||||
|
families.insert("Bookman-Light"); |
||||||
|
families.insert("Bookman-LightItalic"); |
||||||
|
families.insert("Helvetica-Narrow"); |
||||||
|
families.insert("Helvetica-Narrow-Bold"); |
||||||
|
families.insert("Helvetica-Narrow-Oblique"); |
||||||
|
families.insert("Helvetica-Narrow-BoldOblique"); |
||||||
|
families.insert("NewCenturySchlbk-Roman"); |
||||||
|
families.insert("NewCenturySchlbk-Italic"); |
||||||
|
families.insert("NewCenturySchlbk-Bold"); |
||||||
|
families.insert("NewCenturySchlbk-BoldItalic"); |
||||||
|
families.insert("Palatino-Roman"); |
||||||
|
families.insert("Palatino-Italic"); |
||||||
|
families.insert("Palatino-Bold"); |
||||||
|
families.insert("Palatino-BoldItalic"); |
||||||
|
families.insert("ZapfChancery-MediumItalic"); |
||||||
|
families.insert("ZapfDingbats"); |
||||||
|
|
||||||
|
default_family="Times-Roman"; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
const double gmt_projection::default_width=10.0; |
||||||
|
const double gmt_pen::default_width=1.0; |
||||||
|
const double gmt_dash::default_width=gmt_pen::default_width; |
||||||
|
const double gmt_font::default_size=12.0; |
||||||
|
std::string gmt_font::default_family; |
||||||
|
std::set<std::string> gmt_font::families; |
@ -0,0 +1,138 @@ |
|||||||
|
#ifndef MODGMT_OBJECTS_H |
||||||
|
#define MODGMT_OBJECTS_H |
||||||
|
#include <cmath> |
||||||
|
#include <map> |
||||||
|
#include <string.h> |
||||||
|
#include <type_traits> |
||||||
|
#include <vector> |
||||||
|
#include "common.h" |
||||||
|
#include "modgmt_structs.h" |
||||||
|
|
||||||
|
template<class GMTStruct> |
||||||
|
class ObjectGMTClass: public ObjectBase |
||||||
|
{ |
||||||
|
static_assert(std::is_base_of<gmt_struct,GMTStruct>::value,"Template parameter of ObjectGMTClass must be gmt_struct-derived type"); |
||||||
|
const static std::string type; |
||||||
|
GMTStruct s; |
||||||
|
public: |
||||||
|
// Constructor
|
||||||
|
ObjectGMTClass(const GMTStruct& n):s(n) {} |
||||||
|
// Pure virtual overrides
|
||||||
|
ObjectBase* Copy() const override {return new ObjectGMTClass(s);} |
||||||
|
bool Print() const override |
||||||
|
{ |
||||||
|
COUT(NORMAL)<<std::endl<<"Object type: "<<Type()<<std::endl; |
||||||
|
COUT(NORMAL)<<"Value: "<<Value()<<std::endl; |
||||||
|
return true; |
||||||
|
} |
||||||
|
std::string Type() const override {return type;} |
||||||
|
const int8_t* Blob(size_t* size) const override { *size=0; return 0; } |
||||||
|
void DeallocBlob(const int8_t* ptr) const override {}; |
||||||
|
|
||||||
|
// Own functions
|
||||||
|
ObjectBase* Get(const std::string& gname) const |
||||||
|
{ |
||||||
|
std::string name=gname; |
||||||
|
tolower(name); |
||||||
|
if("value"==name) return new ObjectString(Value()); |
||||||
|
return OGet(name); |
||||||
|
} |
||||||
|
std::string Value() const {return s.Value();} |
||||||
|
GMTStruct Data() const {return s;} |
||||||
|
|
||||||
|
private: |
||||||
|
// This is class-dependent Get function
|
||||||
|
ObjectBase* OGet(const std::string& name) const {return 0;} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// GMTCoord
|
||||||
|
typedef ObjectGMTClass<struct gmt_coord> ObjectGMTCoord; |
||||||
|
template<> inline ObjectBase* ObjectGMTCoord::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("n"==name || "number"==name) return new ObjectReal(s); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTRegion
|
||||||
|
typedef ObjectGMTClass<struct gmt_region> ObjectGMTRegion; |
||||||
|
template<> inline ObjectBase* ObjectGMTRegion::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("xb"==name) return new ObjectGMTCoord(s.xb); |
||||||
|
if("xe"==name) return new ObjectGMTCoord(s.xe); |
||||||
|
if("yb"==name) return new ObjectGMTCoord(s.yb); |
||||||
|
if("ye"==name) return new ObjectGMTCoord(s.ye); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTProjection
|
||||||
|
typedef ObjectGMTClass<struct gmt_projection> ObjectGMTProjection; |
||||||
|
template<> inline ObjectBase* ObjectGMTProjection::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("xb"==name) return new ObjectGMTCoord(s.region.xb); |
||||||
|
if("xe"==name) return new ObjectGMTCoord(s.region.xe); |
||||||
|
if("yb"==name) return new ObjectGMTCoord(s.region.yb); |
||||||
|
if("ye"==name) return new ObjectGMTCoord(s.region.ye); |
||||||
|
if("width"==name) return new ObjectReal(s.rwidth); |
||||||
|
if("height"==name) return new ObjectReal(s.rheight); |
||||||
|
if("region"==name) return new ObjectGMTRegion(s.region); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTColor
|
||||||
|
typedef ObjectGMTClass<struct gmt_color> ObjectGMTColor; |
||||||
|
template<> inline ObjectBase* ObjectGMTColor::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("gray"==name || "grey"==name) return new ObjectReal(s.Gray()); |
||||||
|
if("r"==name || "red"==name) return new ObjectReal(s.R()); |
||||||
|
if("g"==name || "green"==name) return new ObjectReal(s.G()); |
||||||
|
if("b"==name || "blue"==name) return new ObjectReal(s.B()); |
||||||
|
if("h"==name || "hue"==name) return new ObjectReal(s.H()); |
||||||
|
if("s"==name || "saturation"==name) return new ObjectReal(s.S()); |
||||||
|
if("v"==name || "value"==name) return new ObjectReal(s.V()); |
||||||
|
if("c"==name || "cyan"==name) return new ObjectReal(s.C()); |
||||||
|
if("m"==name || "magenta"==name) return new ObjectReal(s.M()); |
||||||
|
if("y"==name || "yellow"==name) return new ObjectReal(s.Y()); |
||||||
|
if("k"==name || "black"==name) return new ObjectReal(s.K()); |
||||||
|
if("t"==name || "transparency"==name) return new ObjectReal(s.transparency); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTDash
|
||||||
|
typedef ObjectGMTClass<struct gmt_dash> ObjectGMTDash; |
||||||
|
|
||||||
|
// GMTPen
|
||||||
|
typedef ObjectGMTClass<struct gmt_pen> ObjectGMTPen; |
||||||
|
template<> inline ObjectBase* ObjectGMTPen::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("w"==name || "width"==name) return new ObjectReal(s.width); |
||||||
|
if("c"==name || "color"==name) return new ObjectGMTColor(s.color); |
||||||
|
if("d"==name || "dash"==name) return new ObjectGMTDash(s.dash); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTFont
|
||||||
|
typedef ObjectGMTClass<struct gmt_font> ObjectGMTFont; |
||||||
|
template<> inline ObjectBase* ObjectGMTFont::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("s"==name || "size"==name) return new ObjectReal(s.size); |
||||||
|
if("f"==name || "family"==name)return new ObjectString(s.family); |
||||||
|
if("c"==name || "color"==name) return new ObjectGMTColor(s.color); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// GMTLayer
|
||||||
|
typedef ObjectGMTClass<struct gmt_layer> ObjectGMTLayer; |
||||||
|
template<> inline ObjectBase* ObjectGMTLayer::OGet(const std::string& name) const |
||||||
|
{ |
||||||
|
if("proj"==name || "projection"==name) return new ObjectGMTProjection(s.proj); |
||||||
|
if("w"==name || "width"==name) return new ObjectReal(s.proj.rwidth); |
||||||
|
if("h"==name || "height"==name) return new ObjectReal(s.proj.rheight); |
||||||
|
if("shiftx"==name) return new ObjectReal(s.shiftx); |
||||||
|
if("shifty"==name) return new ObjectReal(s.shifty); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
template<> const int8_t* ObjectGMTLayer::Blob(size_t* size) const; |
||||||
|
template<> void ObjectGMTLayer::DeallocBlob(const int8_t* ptr) const; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,297 @@ |
|||||||
|
#ifndef MODGMT_PARAM_H |
||||||
|
#define MODGMT_PARAM_H |
||||||
|
#include "modgmt_strcomp.h" |
||||||
|
#include "common.h" |
||||||
|
|
||||||
|
// Common ancestor for all parameters
|
||||||
|
template<class Converter, bool Optional> |
||||||
|
class Parameter |
||||||
|
{ |
||||||
|
using ValueType=typename Converter::ValueType; |
||||||
|
std::string name; // Used for error reporting
|
||||||
|
bool initialised; |
||||||
|
Converter conv; |
||||||
|
ValueType val; |
||||||
|
|
||||||
|
template<bool hasDefault, class Conv=Converter> |
||||||
|
struct Adapter; |
||||||
|
template<class Conv> |
||||||
|
struct Adapter<true,Conv> {static const typename Conv::ValueType& Val(const Conv& cnv) {return cnv.Default();}}; |
||||||
|
template<class Conv> |
||||||
|
struct Adapter<false,Conv> {static typename Conv::ValueType Val(const Conv& cnv) {return typename Conv::ValueType();}}; |
||||||
|
|
||||||
|
template<class C> |
||||||
|
struct CheckDefault |
||||||
|
{ |
||||||
|
private: |
||||||
|
static void detect(...); |
||||||
|
template<class T> static decltype(std::declval<T>().Default()) detect(T); |
||||||
|
public: |
||||||
|
static constexpr bool value=std::is_same<ValueType, typename std::decay<decltype(detect(std::declval<C>()))>::type>::value; |
||||||
|
}; |
||||||
|
|
||||||
|
protected: |
||||||
|
Parameter(Parameter&&) = delete; |
||||||
|
Parameter(const Parameter&) = delete; |
||||||
|
Parameter() = delete; |
||||||
|
|
||||||
|
template<class... Args> |
||||||
|
Parameter(std::string&& str, Args... args): name(std::move(str)), initialised(false), conv(args...) |
||||||
|
{ |
||||||
|
val=Adapter<CheckDefault<Converter>::value>::Val(conv); |
||||||
|
} |
||||||
|
template<class... Args> |
||||||
|
Parameter(const std::string& str, Args... args): name(str), initialised(false), conv(args...) |
||||||
|
{ |
||||||
|
val=Adapter<CheckDefault<Converter>::value>::Val(conv); |
||||||
|
} |
||||||
|
|
||||||
|
void SetState(bool newini) {initialised=newini;} |
||||||
|
|
||||||
|
public: |
||||||
|
bool Init(const ObjectBase* p, std::string& err) |
||||||
|
{ |
||||||
|
std::string cerr; |
||||||
|
bool res=true; |
||||||
|
ValueType tval=conv.Convert(p,&res,cerr); |
||||||
|
SetState(res); |
||||||
|
if(res) val=std::move(tval); |
||||||
|
else err=std::move(cerr); |
||||||
|
return res; |
||||||
|
} |
||||||
|
bool Initialised() const {return initialised;} |
||||||
|
bool Exist() const {return initialised;} |
||||||
|
const std::string& Name() const {return name;} |
||||||
|
constexpr bool isOptional() const {return Optional;} |
||||||
|
const ValueType& Value() {return val;} |
||||||
|
const ValueType* operator->() const {return &val;} |
||||||
|
operator const ValueType&() {return val;} |
||||||
|
void Reset() {initialised=false; val=Adapter<CheckDefault<Converter>::value>::Val(conv);} |
||||||
|
|
||||||
|
static constexpr bool optional=Optional; |
||||||
|
using ConverterType=Converter; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Class for parameter which must be in named pair
|
||||||
|
template <class Converter, bool O> |
||||||
|
class NamedParameter: public TemplateComparator, public Parameter<Converter,O> |
||||||
|
{ |
||||||
|
public: |
||||||
|
using AcceptableObject=void; |
||||||
|
template<class... Args> |
||||||
|
NamedParameter(const std::string& t, Args... args):TemplateComparator(t),Parameter<Converter,O>(Template2Name(),args...) {} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Class for parameter which can be in named pair or as object of type Object
|
||||||
|
template <class Converter, bool O, class Object> |
||||||
|
class NamedFreeParameter: public NamedParameter<Converter,O> |
||||||
|
{ |
||||||
|
public: |
||||||
|
using AcceptableObject=Object; |
||||||
|
template<class... Args> |
||||||
|
NamedFreeParameter(Args... args):NamedParameter<Converter,O>(args...) {} |
||||||
|
}; |
||||||
|
|
||||||
|
// Class for parameter which can be in some positions in list
|
||||||
|
template <class Converter, bool O> |
||||||
|
class PositionalParameter: public Parameter<Converter,O> |
||||||
|
{ |
||||||
|
public: |
||||||
|
template<class... Args> |
||||||
|
PositionalParameter(Args... args):Parameter<Converter,O>(args...) {} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Base class for ParseNamedParameters and ParsePositionalParameters
|
||||||
|
class ParseParameters |
||||||
|
{ |
||||||
|
protected: |
||||||
|
std::string err; |
||||||
|
ParseParameters():err() {} |
||||||
|
ParseParameters(const ParseParameters&) = delete; |
||||||
|
ParseParameters(ParseParameters&&) = delete; |
||||||
|
|
||||||
|
public: |
||||||
|
std::string Error() const {return err;} |
||||||
|
bool Ok() const {return err.empty();} |
||||||
|
operator bool() const {return Ok();} |
||||||
|
}; |
||||||
|
|
||||||
|
// Parsing positional parameters
|
||||||
|
class ParsePositionalParameters: public ParseParameters |
||||||
|
{ |
||||||
|
ParsePositionalParameters() = delete; |
||||||
|
ParsePositionalParameters(const ParsePositionalParameters&) = delete; |
||||||
|
ParsePositionalParameters(ParsePositionalParameters&&) = delete; |
||||||
|
|
||||||
|
// Main parsing function
|
||||||
|
template <class Par, class... Args> |
||||||
|
void Parse(ObjectList::IndexType i, ObjectList::IndexType max, const ObjectList* ol, Par& param, Args&... args) |
||||||
|
{ |
||||||
|
// Check types of arguments
|
||||||
|
static_assert(std::is_same<PositionalParameter<typename Par::ConverterType, Par::optional>,Par>::value,"ParsePositionalParameters argument(s) must be PositionalParameter"); |
||||||
|
|
||||||
|
// Check if parameter already initialised. This is code error.
|
||||||
|
if(param.Initialised()) |
||||||
|
{ |
||||||
|
err="Parameter "+param.Name()+" already initialised. This is code error."; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// List is ended
|
||||||
|
if(i>=max) |
||||||
|
{ |
||||||
|
// Parameter is optional, skip it
|
||||||
|
if(Par::optional) Parse(i,max,ol,args...); |
||||||
|
// Parameter is required, this is an error
|
||||||
|
else err="Parameter "+param.Name()+" is required, but can't be setted because list is ended"; |
||||||
|
} |
||||||
|
// Initialise from some list element
|
||||||
|
else |
||||||
|
{ |
||||||
|
bool res=param.Init(ol->At(i),err); |
||||||
|
// All Ok, continue to next element in list
|
||||||
|
if(res) Parse(i+1,max,ol,args...); |
||||||
|
else |
||||||
|
{ |
||||||
|
// All Ok, optional parameter may be absent, try to initialise next parameter by same list element
|
||||||
|
if(Par::optional) Parse(i,max,ol,args...); |
||||||
|
// Error, required parameter not initialised
|
||||||
|
else err="Can't initialise parameter "+param.Name()+" from list element number "+ToString(i)+": "+err; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Bottom of recursion
|
||||||
|
void Parse(ObjectList::IndexType i, ObjectList::IndexType max, const ObjectList* ol) {if(i<max) err="There are excess elements in list";} |
||||||
|
|
||||||
|
public: |
||||||
|
template <class Converter, bool optional, class... Args> |
||||||
|
ParsePositionalParameters(const ObjectList* ol, PositionalParameter<Converter,optional>& p1, Args&... args) {Parse(0,ol->Size(),ol,p1,args...);} |
||||||
|
template <class Converter, bool optional, class... Args> |
||||||
|
ParsePositionalParameters(const ObjectList* ol, ObjectList::IndexType min, ObjectList::IndexType max, PositionalParameter<Converter,optional>& p1, Args&... args) {Parse(min,std::min(max,ol->Size()),ol,p1,args...);} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Parsing named parameters
|
||||||
|
class ParseNamedParameters: public ParseParameters |
||||||
|
{ |
||||||
|
ParseNamedParameters() = delete; |
||||||
|
ParseNamedParameters(const ParseNamedParameters&) = delete; |
||||||
|
ParseNamedParameters(ParseNamedParameters&&) = delete; |
||||||
|
|
||||||
|
// Parsing function for elements without names
|
||||||
|
// ob - object from which we initialise parameter param.
|
||||||
|
// init - is ob was already used for initialise something.
|
||||||
|
// args - other parameters
|
||||||
|
// Function try to initialise parameter param, if param accepted real type of ob for initialisation, else function try to initialise next parameter in args.
|
||||||
|
// Function return error if initialisation of parameter failed or if two parameters can be initialised from ob.
|
||||||
|
template <class Par, class... Args> |
||||||
|
bool ParseSingle(const ObjectBase* ob, bool init, Par& param, Args&... args) |
||||||
|
{ |
||||||
|
// Check types of arguments
|
||||||
|
static_assert(std::is_same<NamedParameter<typename Par::ConverterType, Par::optional>,Par>::value || std::is_same<NamedFreeParameter<typename Par::ConverterType, Par::optional, typename Par::AcceptableObject>,Par>::value,"ParseNamedParameters argument(s) must be NamedParameter or NamedFreeParameter"); |
||||||
|
|
||||||
|
OBType<typename Par::AcceptableObject> o(ob); |
||||||
|
if(o && init) |
||||||
|
{ |
||||||
|
err="Object of type "+ob->Type()+" used for initialisation of two parameters. This is code error."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
if(!o) return ParseSingle(ob,init,args...); // Type mismatch, goto next parameter
|
||||||
|
if(param.Initialised()) |
||||||
|
{ |
||||||
|
err="Parameter "+param.Name()+" can't be initialised from object of type "+ob->Type()+" because it already initialised."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
std::string ierr; |
||||||
|
if(!param.Init(ob,ierr)) |
||||||
|
{ |
||||||
|
err="Parameter "+param.Name()+" can't be initialised from object of type "+ob->Type()+": "+ierr; |
||||||
|
return false; |
||||||
|
} |
||||||
|
return ParseSingle(ob,true,args...); |
||||||
|
} |
||||||
|
// Bottom of recursion
|
||||||
|
bool ParseSingle(const ObjectBase* ob, bool init) const {return true;} |
||||||
|
|
||||||
|
// Parsing function for elements in pairs
|
||||||
|
// op - pair from which we initialise parameter param.
|
||||||
|
// pname - name of parameter already initialised from op (or empty string).
|
||||||
|
// args - other parameters
|
||||||
|
// Function try to initialise parameter param, if pair name corresponding to param template, else function try to initialise next parameter in args.
|
||||||
|
// Function return error if initialisation of parameter failed or if two parameters can be initialised from op.
|
||||||
|
template <class Par, class... Args> |
||||||
|
bool ParsePair(const ObjectPair* op, std::string& pname, Par& param, Args&... args) |
||||||
|
{ |
||||||
|
// Check types of arguments
|
||||||
|
static_assert(std::is_same<NamedParameter<typename Par::ConverterType, Par::optional>,Par>::value || std::is_same<NamedFreeParameter<typename Par::ConverterType, Par::optional, typename Par::AcceptableObject>,Par>::value,"ParseNamedParameters argument(s) must be NamedParameter or NamedFreeParameter"); |
||||||
|
|
||||||
|
bool cmp=param.Compare(op->Name()); |
||||||
|
if(cmp && !pname.empty()) |
||||||
|
{ |
||||||
|
err="Element "+op->Name()+" can be used for initialisation of two parameters: "+pname+" and "+param.Name(); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if(!cmp) return ParsePair(op,pname,args...); // Name mismatch, goto next parameter
|
||||||
|
pname=param.Name(); |
||||||
|
if(param.Initialised()) |
||||||
|
{ |
||||||
|
err="Parameter "+param.Name()+" can't be initialised from element "+op->Name()+" because it already initialised."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
std::string ierr; |
||||||
|
if(!param.Init(op->Value(),ierr)) |
||||||
|
{ |
||||||
|
err="Parameter "+param.Name()+" can't be initialised from element "+op->Name()+": "+ierr; |
||||||
|
return false; |
||||||
|
} |
||||||
|
return ParsePair(op,pname,args...); |
||||||
|
} |
||||||
|
// Bottom of recursion
|
||||||
|
bool ParsePair(const ObjectPair* op, std::string& pname) const {return true;} |
||||||
|
|
||||||
|
template <class Par, class... Args> |
||||||
|
void CheckRequired(const Par& param, Args&... args) |
||||||
|
{ |
||||||
|
if((Par::optional || param.Initialised())) CheckRequired(args...); |
||||||
|
else err="Parameter "+param.Name()+" is required, but not initialised"; |
||||||
|
} |
||||||
|
// Bottom of recursion
|
||||||
|
void CheckRequired() const {} |
||||||
|
|
||||||
|
public: |
||||||
|
template <class... Args> |
||||||
|
ParseNamedParameters(const ObjectList* ol, Args&... args) |
||||||
|
{ |
||||||
|
// Initialisation
|
||||||
|
std::string pname; |
||||||
|
for(ObjectList::const_iterator i=ol->begin();i!=ol->end();++i) |
||||||
|
{ |
||||||
|
pname.erase(); |
||||||
|
OBType<ObjectPair> p(*i); |
||||||
|
if( !(p?ParsePair(p,pname,args...):ParseSingle(*i,false,args...)) ) break; |
||||||
|
} |
||||||
|
if(!Ok()) return; // Error on initialisation phase
|
||||||
|
// Check if all required parameters are initialised
|
||||||
|
CheckRequired(args...); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template<class Converter> |
||||||
|
using ONPar=NamedParameter<Converter,true>; |
||||||
|
template<class Converter> |
||||||
|
using RNPar=NamedParameter<Converter,false>; |
||||||
|
|
||||||
|
template<class Converter, class Object> |
||||||
|
using ONFPar=NamedFreeParameter<Converter,true,Object>; |
||||||
|
template<class Converter, class Object> |
||||||
|
using RNFPar=NamedFreeParameter<Converter,false,Object>; |
||||||
|
|
||||||
|
template<class Converter> |
||||||
|
using OPosPar=PositionalParameter<Converter,true>; |
||||||
|
template<class Converter> |
||||||
|
using RPosPar=PositionalParameter<Converter,false>; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,139 @@ |
|||||||
|
#include "modgmt_strcomp.h" |
||||||
|
|
||||||
|
TemplateComparator::Block::pBlock TemplateComparator::Parse() |
||||||
|
{ |
||||||
|
size_t e=0; |
||||||
|
struct Block* blk; |
||||||
|
struct Block* root; |
||||||
|
auto c=s[e]; |
||||||
|
bool init,next; |
||||||
|
|
||||||
|
// First symbol
|
||||||
|
if('['==c || '('==c) blk=new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS); |
||||||
|
else blk=new Block(e,e+1); |
||||||
|
root=blk; |
||||||
|
init=root->type!=Block::TEXT; |
||||||
|
next=!init; |
||||||
|
|
||||||
|
e++; |
||||||
|
while(e<s.length()) |
||||||
|
{ |
||||||
|
c=s[e]; |
||||||
|
|
||||||
|
switch(c) |
||||||
|
{ |
||||||
|
case '[': |
||||||
|
case '(': |
||||||
|
{ |
||||||
|
(next?blk->next:blk->child).reset(new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS,(next?blk->parent:blk))); |
||||||
|
blk=(next?blk->next:blk->child).get(); |
||||||
|
init=true; |
||||||
|
next=false; |
||||||
|
break; |
||||||
|
} |
||||||
|
case ']': |
||||||
|
case ')': |
||||||
|
{ |
||||||
|
blk=const_cast<struct Block*>(blk->parent); |
||||||
|
init=true; |
||||||
|
next=true; |
||||||
|
break; |
||||||
|
} |
||||||
|
case '|': {blk->next.reset(new Block(Block::DELIM,blk->parent)); blk=blk->next.get(); init=next=true; break;} |
||||||
|
default: |
||||||
|
{ |
||||||
|
if(init) |
||||||
|
{ |
||||||
|
(next?blk->next:blk->child).reset(new Block(e,e+1,(next?blk->parent:blk))); |
||||||
|
blk=(next?blk->next:blk->child).get(); |
||||||
|
} |
||||||
|
else blk->e=e+1; |
||||||
|
init=false; |
||||||
|
next=true; |
||||||
|
} |
||||||
|
} |
||||||
|
e++; |
||||||
|
} |
||||||
|
return Block::pBlock(root); |
||||||
|
} |
||||||
|
|
||||||
|
void TemplateComparator::InitCursors(const struct TemplateComparator::Block* blk) |
||||||
|
{ |
||||||
|
switch(blk->type) |
||||||
|
{ |
||||||
|
case Block::TEXT: {cursors.insert({blk,0}); break;} |
||||||
|
case Block::OPTIONAL: |
||||||
|
{ |
||||||
|
auto b=blk; |
||||||
|
InitCursors(b->child.get()); |
||||||
|
while(true) |
||||||
|
{ |
||||||
|
if(!b->next) break; |
||||||
|
b=b->next.get(); |
||||||
|
InitCursors(b); |
||||||
|
if(b->type!=Block::OPTIONAL) break; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case Block::VARIANTS: |
||||||
|
{ |
||||||
|
auto b=blk->child.get(); |
||||||
|
while(true) |
||||||
|
{ |
||||||
|
InitCursors(b); |
||||||
|
while(b->type!=Block::DELIM) |
||||||
|
{ |
||||||
|
if(!b->next) break; |
||||||
|
b=b->next.get(); |
||||||
|
} |
||||||
|
if(!b->next) break; |
||||||
|
b=b->next.get(); |
||||||
|
} |
||||||
|
} |
||||||
|
default: {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool TemplateComparator::CmpSmb(const char c) |
||||||
|
{ |
||||||
|
pCursor p=cursors.cbegin(); |
||||||
|
bool res=false; |
||||||
|
|
||||||
|
// Compare symbol with all cursors
|
||||||
|
while(p!=cursors.end()) |
||||||
|
{ |
||||||
|
if(p->compare(s,c)) {res=true; p++;} |
||||||
|
else p=cursors.erase(p); |
||||||
|
} |
||||||
|
|
||||||
|
Cursors old(std::move(cursors)); |
||||||
|
for(const auto& p:old) |
||||||
|
{ |
||||||
|
auto blk=p.block; |
||||||
|
// Increment cursors
|
||||||
|
if(blk->b+p.offset+1<blk->e) cursors.insert({blk,p.offset+1}); // Advance in current block
|
||||||
|
else // Move to next block
|
||||||
|
{ |
||||||
|
if(!blk->next || blk->next->type==Block::DELIM) // End of chain, must go up
|
||||||
|
{ |
||||||
|
while(blk->parent!=nullptr) |
||||||
|
{ |
||||||
|
blk=blk->parent; |
||||||
|
if(!blk->next || blk->next->type==Block::DELIM) continue; |
||||||
|
InitCursors(blk->next.get()); |
||||||
|
} |
||||||
|
} |
||||||
|
else InitCursors(blk->next.get()); // Next block in chain
|
||||||
|
} |
||||||
|
|
||||||
|
// Try to leave optional blocks
|
||||||
|
blk=p.block; |
||||||
|
while(blk->parent!=nullptr) |
||||||
|
{ |
||||||
|
blk=blk->parent; |
||||||
|
if(blk->type!=Block::OPTIONAL || !blk->next || blk->next->type==Block::DELIM) continue; |
||||||
|
InitCursors(blk->next.get()); |
||||||
|
} |
||||||
|
} |
||||||
|
return res; |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
#ifndef MODGMT_STRCOMP_H |
||||||
|
#define MODGMT_STRCOMP_H |
||||||
|
#include <memory> |
||||||
|
#include <set> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
// Compare string with template
|
||||||
|
class TemplateComparator |
||||||
|
{ |
||||||
|
TemplateComparator() = delete; |
||||||
|
TemplateComparator(const TemplateComparator&) = delete; |
||||||
|
TemplateComparator(TemplateComparator&&) = delete; |
||||||
|
|
||||||
|
struct Block |
||||||
|
{ |
||||||
|
using pBlock=std::unique_ptr<struct Block>; |
||||||
|
enum Type {NOTDEF,TEXT,OPTIONAL,VARIANTS,DELIM}; |
||||||
|
size_t b,e; |
||||||
|
Type type; |
||||||
|
const struct Block* parent; |
||||||
|
pBlock next,child; |
||||||
|
|
||||||
|
Block() = delete; |
||||||
|
Block(const struct Block&) = delete; |
||||||
|
Block(struct Block&&) = delete; |
||||||
|
|
||||||
|
Block(Type t, const struct Block* p=nullptr):b(0),e(0),type(t),parent(p),next(nullptr),child(nullptr) {} |
||||||
|
Block(size_t bb, size_t ee, const struct Block* p=nullptr):b(bb),e(ee),type(TEXT),parent(p),next(nullptr),child(nullptr) {} |
||||||
|
}; |
||||||
|
|
||||||
|
struct Cursor |
||||||
|
{ |
||||||
|
const struct Block* block; |
||||||
|
size_t offset; |
||||||
|
bool operator <(const struct Cursor& c) const {return block<c.block;} |
||||||
|
bool compare(const std::string& str, const char c) const {return c==str[block->b+offset];} |
||||||
|
Cursor(const struct Block* b, size_t o):block(b),offset(o) {} |
||||||
|
}; |
||||||
|
|
||||||
|
using Cursors=std::set<struct Cursor>; |
||||||
|
using pCursor=std::set<struct Cursor>::const_iterator; |
||||||
|
|
||||||
|
Block::pBlock Parse(); |
||||||
|
void InitCursors(const struct Block* blk); |
||||||
|
bool CmpSmb(const char c); |
||||||
|
|
||||||
|
Block::pBlock root; |
||||||
|
Cursors cursors; |
||||||
|
const std::string s; |
||||||
|
|
||||||
|
void Reset() |
||||||
|
{ |
||||||
|
cursors.clear(); |
||||||
|
InitCursors(root.get()); |
||||||
|
} |
||||||
|
|
||||||
|
public: |
||||||
|
TemplateComparator(const char* str):s(str) {root=Parse();} |
||||||
|
TemplateComparator(const std::string& str):s(str) {root=Parse();} |
||||||
|
TemplateComparator(std::string&& str):s(std::move(str)) {root=Parse();} |
||||||
|
|
||||||
|
bool Compare(const std::string& str) |
||||||
|
{ |
||||||
|
Reset(); |
||||||
|
for(size_t pos=0; pos<str.length(); ++pos) if(!CmpSmb(str[pos])) return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
std::string Template2Name() const |
||||||
|
{ |
||||||
|
const struct Block* b=root.get(); |
||||||
|
std::string res; |
||||||
|
while(true) |
||||||
|
{ |
||||||
|
// Processing current block
|
||||||
|
switch(b->type) |
||||||
|
{ |
||||||
|
case(Block::TEXT): {res+=s.substr(b->b,b->e-b->b); break;} |
||||||
|
case(Block::OPTIONAL): |
||||||
|
case(Block::VARIANTS): {b=b->child.get(); goto next;} |
||||||
|
case(Block::DELIM): {b=b->parent; break;} |
||||||
|
default: {} |
||||||
|
} |
||||||
|
// Go to next block
|
||||||
|
while(true) |
||||||
|
{ |
||||||
|
if(nullptr!=b->next) {b=b->next.get(); goto next;} |
||||||
|
if(nullptr!=b->parent) b=b->parent; |
||||||
|
else break; |
||||||
|
} |
||||||
|
if(nullptr==b->next && nullptr==b->parent) break; |
||||||
|
next: ; |
||||||
|
} |
||||||
|
return res; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,900 @@ |
|||||||
|
#ifndef MODGMT_STRUCT_H |
||||||
|
#define MODGMT_STRUCT_H |
||||||
|
#include <cinttypes> |
||||||
|
#include <cmath> |
||||||
|
#include <map> |
||||||
|
#include <vector> |
||||||
|
#include "common.h" |
||||||
|
#include "modgmt_colornames.h" |
||||||
|
#include "modgmt_strcomp.h" |
||||||
|
|
||||||
|
// Centimeters to GMT points scale factor
|
||||||
|
// 1 inch = 72 pt = 2.54 cm --> 1 cm = 72/2.54 pt
|
||||||
|
// GMT's own scaling factor is 0.06
|
||||||
|
inline static double cm2GMT(double cm) |
||||||
|
{ |
||||||
|
static const double scale=(72.0/2.54)/0.06; |
||||||
|
return cm*scale; |
||||||
|
} |
||||||
|
|
||||||
|
// Helper template for checking double numbers acquired from Source with some Policies.
|
||||||
|
// Main definition, never instantiated
|
||||||
|
template<class Source, class... Policies> |
||||||
|
class GetDouble; |
||||||
|
|
||||||
|
// Recursive definition
|
||||||
|
template<class Source, class Policy, class... Policies> |
||||||
|
class GetDouble<Source, Policy, Policies...>: public GetDouble<Source, Policies...> |
||||||
|
{ |
||||||
|
Policy p; |
||||||
|
public: |
||||||
|
GetDouble(GetDouble&&) = delete; |
||||||
|
GetDouble(GetDouble&) = delete; |
||||||
|
template<class... Args> |
||||||
|
GetDouble(Args... args):GetDouble<Source,Policies...>(args...) {}; |
||||||
|
double operator()(bool* suc, std::string& err) const {return p(GetDouble<Source,Policies...>::operator()(suc,err),suc,err);} |
||||||
|
}; |
||||||
|
|
||||||
|
// Bottom of recursion
|
||||||
|
template<class Source> |
||||||
|
class GetDouble<Source>: public Source |
||||||
|
{ |
||||||
|
public: |
||||||
|
GetDouble(GetDouble&&) = delete; |
||||||
|
GetDouble(GetDouble&) = delete; |
||||||
|
GetDouble() = delete; |
||||||
|
template<class... Args> |
||||||
|
GetDouble(Args... args):Source(args...) {}; |
||||||
|
double operator()(bool* suc, std::string& err) const {return Source::operator()(suc, err);} |
||||||
|
}; |
||||||
|
|
||||||
|
// We use rational representation of floating point number, because double type values not allowed as template parameter
|
||||||
|
// Policy to check if value is greater or equal num/denum
|
||||||
|
template<int32_t num, uint32_t denum=1, bool equal=true> |
||||||
|
class PMin |
||||||
|
{ |
||||||
|
static bool Compare(double d1, double d2) {return equal?(d1<=d2):(d1<d2);} |
||||||
|
|
||||||
|
public: |
||||||
|
double operator()(double v, bool* suc, std::string& err) const |
||||||
|
{ |
||||||
|
if(Compare(v,static_cast<double>(num)/denum)) |
||||||
|
{ |
||||||
|
*suc=false; |
||||||
|
if(err.empty()) err="Value "+ToString(v)+" must be greater "+(equal?"or equal ":"")+"then "+ToString(num)+((denum==1)?"":("/"+ToString(denum))); |
||||||
|
} |
||||||
|
return v; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// Policy to check if value is lesser or equal num/denum
|
||||||
|
template<int32_t num, uint32_t denum=1, bool equal=true> |
||||||
|
class PMax |
||||||
|
{ |
||||||
|
static bool Compare(double d1, double d2) {return equal?(d1>=d2):(d1>d2);} |
||||||
|
|
||||||
|
public: |
||||||
|
double operator()(double v, bool* suc, std::string& err) const |
||||||
|
{ |
||||||
|
if(Compare(v,static_cast<double>(num)/denum)) |
||||||
|
{ |
||||||
|
*suc=false; |
||||||
|
if(err.empty()) err="Value "+ToString(v)+" must be lesser "+(equal?"or equal ":"")+"then "+ToString(num)+((denum==1)?"":("/"+ToString(denum))); |
||||||
|
} |
||||||
|
return v; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// Get double value from string or number
|
||||||
|
class SourceValue |
||||||
|
{ |
||||||
|
double d; |
||||||
|
std::string err; |
||||||
|
public: |
||||||
|
SourceValue(const std::string& s) {if(!str2double(s,&d)) err="Can't convert string \""+s+"\" to double value";} |
||||||
|
SourceValue(double s):d(s) {} |
||||||
|
double operator()(bool* suc, std::string& ierr) const |
||||||
|
{ |
||||||
|
if(!err.empty()) {*suc=false; ierr=err;} |
||||||
|
return d; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// Helper types for colors
|
||||||
|
typedef GetDouble<SourceValue,PMin<0>,PMax<255> > Value2RGB; |
||||||
|
typedef GetDouble<SourceValue,PMin<0>,PMax<360> > Value2Hue; |
||||||
|
typedef GetDouble<SourceValue,PMin<0>,PMax< 1 > > Value2SV; |
||||||
|
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2CMYK; |
||||||
|
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2Transp; |
||||||
|
// Helper type for pens and dashes
|
||||||
|
typedef GetDouble<SourceValue,PMin<0> > Value2Width; |
||||||
|
|
||||||
|
class gmt_struct {}; // Base type for all gmt structures
|
||||||
|
|
||||||
|
// Coordinate
|
||||||
|
struct gmt_coord: public gmt_struct |
||||||
|
{ |
||||||
|
bool isdeg; |
||||||
|
union |
||||||
|
{ |
||||||
|
double r; |
||||||
|
struct |
||||||
|
{ |
||||||
|
bool sign; |
||||||
|
uint16_t d; |
||||||
|
uint8_t m; |
||||||
|
double s; |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
std::string Value() const |
||||||
|
{ |
||||||
|
if(!isdeg) return ToString(r); |
||||||
|
else return (sign?"":"-")+ToString(d)+":"+ToString(m)+(s==0?"":":"+ToString(s)); |
||||||
|
} |
||||||
|
operator double() const |
||||||
|
{ |
||||||
|
if(isdeg) return (d+(m+s/60.0)/60.0)*(sign?1:-1); |
||||||
|
else return r; |
||||||
|
} |
||||||
|
|
||||||
|
bool Convert(const std::string& str, std::string& err) |
||||||
|
{ |
||||||
|
WordList wl; |
||||||
|
WordList::const_iterator cw; |
||||||
|
wl=Split(str,":",true); |
||||||
|
if(1==wl.size()) // No dd:mm
|
||||||
|
{ |
||||||
|
isdeg=false; |
||||||
|
bool res=str2double(str,&r); |
||||||
|
if(!res) err="Can't convert string "+str+" to double value"; |
||||||
|
return res; |
||||||
|
} |
||||||
|
if(0==wl.size() || wl.size()>3) {err="String "+str+" have incorrect format for geographic coordinate, must be ddd[:mm[:ss[.fff]]]"; return false;} |
||||||
|
|
||||||
|
isdeg=true; |
||||||
|
int64_t res; |
||||||
|
|
||||||
|
// degrees
|
||||||
|
cw=wl.begin(); |
||||||
|
if(!str2int(*cw,&res)) {err="Can't convert "+*cw+" to integer"; return false;} |
||||||
|
if(res>360 || res<-360) res%=360; |
||||||
|
sign=(std::string::npos==cw->find('-')); |
||||||
|
d=static_cast<uint16_t>(sign?res:-res); |
||||||
|
// minutes
|
||||||
|
cw++; |
||||||
|
if(!str2int(*cw,&res)) {err="Can't convert "+*cw+" to integer"; return false;} |
||||||
|
if(res<0 || res>=60) {err="Minutes must be not lesser then 0 and lesser then 60"; return false;} |
||||||
|
m=static_cast<uint8_t>(res); |
||||||
|
s=0; |
||||||
|
|
||||||
|
// seconds
|
||||||
|
cw++; |
||||||
|
if(wl.end()==cw) return true; // No seconds
|
||||||
|
if(!str2double(*cw,&s) ) {err="Can't convert "+*cw+" to double"; return false;} |
||||||
|
if(s<0.0 || s>=60.0) {err="Seconds must be not lesser then 0 and lesser then 60"; return false;} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool Convert(double num, std::string& err) |
||||||
|
{ |
||||||
|
isdeg=false; |
||||||
|
r=num; |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Region
|
||||||
|
struct gmt_region: public gmt_struct |
||||||
|
{ |
||||||
|
enum Type {NORMAL,BBOX,GLOBAL360,GLOBAL180}; |
||||||
|
Type type; |
||||||
|
struct gmt_coord xb,xe,yb,ye; |
||||||
|
|
||||||
|
std::string Value() const |
||||||
|
{ |
||||||
|
switch(type) |
||||||
|
{ |
||||||
|
case(NORMAL): return std::string("-R")+xb.Value()+"/"+xe.Value()+"/"+yb.Value()+"/"+ye.Value(); |
||||||
|
case(BBOX): return std::string("-R")+xb.Value()+"/"+yb.Value()+"/"+xe.Value()+"/"+ye.Value()+"r"; |
||||||
|
case(GLOBAL360): return "-Rg"; |
||||||
|
case(GLOBAL180): return "-Rd"; |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
// Only "global", "global180" and "global360"
|
||||||
|
// TODO: add parsing of "-R" strings
|
||||||
|
bool Convert(const std::string& istr, std::string& err) |
||||||
|
{ |
||||||
|
std::string str=istr; |
||||||
|
tolower(str); |
||||||
|
if("global180"==str) |
||||||
|
{ |
||||||
|
type=GLOBAL180; |
||||||
|
xb.Convert(-180.0,err); xe.Convert(180.0,err); |
||||||
|
yb.Convert(-90.0,err); ye.Convert(90.0,err); |
||||||
|
return true; |
||||||
|
} |
||||||
|
if("global360"==str || "global"==str) |
||||||
|
{ |
||||||
|
type=GLOBAL360; |
||||||
|
xb.Convert(0.0,err); xe.Convert(360.0,err); |
||||||
|
yb.Convert(-90.0,err); ye.Convert(90.0,err); |
||||||
|
return true; |
||||||
|
} |
||||||
|
err="Can't convert "+istr+" to region."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Make by coordinates
|
||||||
|
bool Convert(struct gmt_coord ixb, struct gmt_coord ixe, struct gmt_coord iyb, struct gmt_coord iye, bool isbbox=false) |
||||||
|
{ |
||||||
|
type=isbbox?BBOX:NORMAL; |
||||||
|
xb=ixb; yb=iyb; xe=ixe; ye=iye; |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Projection
|
||||||
|
struct gmt_projection: public gmt_struct |
||||||
|
{ |
||||||
|
// OBLIQMERCATOR types
|
||||||
|
enum class OType {NOTDEF,A,B,C}; |
||||||
|
// No UTM (-Ju)
|
||||||
|
enum projection {NOTDEF,XY,CYL_EQU,MERCATOR,TRANSMERCATOR,OBLIQMERCATOR,CASSINI,CYL_EQA,MILLER,CYL_STERE}; |
||||||
|
// Real size in cm of drawing area
|
||||||
|
double rwidth,rheight; |
||||||
|
|
||||||
|
struct gmt_region region; |
||||||
|
projection proj; |
||||||
|
double width; // parameter of projection
|
||||||
|
static const double default_width; |
||||||
|
|
||||||
|
union // other projection parameters
|
||||||
|
{ |
||||||
|
// XY
|
||||||
|
struct {double height;} x; |
||||||
|
// Cylindrical projections
|
||||||
|
// CYL_EQU (Cylindrical Equidistant -Jq)
|
||||||
|
struct {struct gmt_coord stpar,cmer;} q; |
||||||
|
// MERCATOR (-Jm)
|
||||||
|
struct {struct gmt_coord stpar,cmer;} m; |
||||||
|
// TRANSMERCATOR (-Jt)
|
||||||
|
struct {struct gmt_coord cmer,orlat; double scale;} t; |
||||||
|
// OBLIQMERCATOR (-Jo)
|
||||||
|
struct |
||||||
|
{ |
||||||
|
OType type; |
||||||
|
struct gmt_coord clon,clat; |
||||||
|
union |
||||||
|
{ |
||||||
|
struct gmt_coord azimuth; // A
|
||||||
|
struct {struct gmt_coord eqlon,eqlat;}; // B
|
||||||
|
struct {struct gmt_coord polelon,polelat;}; // C
|
||||||
|
}; |
||||||
|
} o; |
||||||
|
// CASSINI (-Jc)
|
||||||
|
struct {struct gmt_coord clon,clat;} c; |
||||||
|
// CYL_EQA (Cylindrical equal-area -Jy)
|
||||||
|
struct {struct gmt_coord stpar,cmer;} y; |
||||||
|
// MILLER (-Jj)
|
||||||
|
struct {struct gmt_coord cmer;} j; |
||||||
|
// CYL_STERE (Cylindrical stereographic -Jcyl_stere)
|
||||||
|
struct {struct gmt_coord stpar,cmer;} cyl_stere; |
||||||
|
}; |
||||||
|
std::string Value() const |
||||||
|
{ |
||||||
|
std::string ret; |
||||||
|
switch(proj) |
||||||
|
{ |
||||||
|
case(XY): {ret="-JX"+ToString(width)+"c/"+ToString(x.height)+"c"; break;} |
||||||
|
case(CYL_EQU): {ret="-JQ"+q.cmer.Value()+"/"+q.stpar.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(MERCATOR): {ret="-JM"+m.cmer.Value()+"/"+m.stpar.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(TRANSMERCATOR): {ret="-JT"+t.cmer.Value()+"/"+t.orlat.Value()+"/"+ToString(width)+"c --PROJ_SCALE_FACTOR="+ToString(t.scale); break;} |
||||||
|
case(OBLIQMERCATOR): |
||||||
|
{ |
||||||
|
switch(o.type) |
||||||
|
{ |
||||||
|
case(OType::A): {ret="-JOa"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.azimuth.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(OType::B): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.eqlon.Value()+"/"+o.eqlat.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(OType::C): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.polelon.Value()+"/"+o.polelat.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
default: return ""; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case(CASSINI): {ret="-JC"+c.clon.Value()+"/"+c.clat.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(CYL_EQA): {ret="-JY"+y.cmer.Value()+"/"+y.stpar.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(MILLER): {ret="-JJ"+j.cmer.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
case(CYL_STERE): {ret="-JCyl_stere/"+cyl_stere.stpar.Value()+"/"+cyl_stere.cmer.Value()+"/"+ToString(width)+"c"; break;} |
||||||
|
default: return ""; |
||||||
|
} |
||||||
|
ret+=" "+region.Value(); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
bool SetType(const std::string& s, std::string& err) |
||||||
|
{ |
||||||
|
proj=NOTDEF; |
||||||
|
std::string str=s; |
||||||
|
tolower(str); |
||||||
|
|
||||||
|
// Handle one symbol cases
|
||||||
|
if(str.size()==1) switch(str[0]) |
||||||
|
{ |
||||||
|
case('c'): {proj=CASSINI; return true;} |
||||||
|
case('j'): {proj=MILLER; return true;} |
||||||
|
case('m'): {proj=MERCATOR; return true;} |
||||||
|
case('o'): {proj=OBLIQMERCATOR; return true;} |
||||||
|
case('q'): {proj=CYL_EQU; return true;} |
||||||
|
case('t'): {proj=TRANSMERCATOR; return true;} |
||||||
|
case('x'): {proj=XY; return true;} |
||||||
|
case('y'): {proj=CYL_EQA; return true;} |
||||||
|
default: break; |
||||||
|
} |
||||||
|
// Handle long GMT names
|
||||||
|
if("cyl_stere"==str) {proj=CYL_STERE; return true;} |
||||||
|
// Handle common names
|
||||||
|
std::string t1; |
||||||
|
for(const auto& m: projnames) |
||||||
|
{ |
||||||
|
TemplateComparator cmp(m.first); |
||||||
|
bool res=cmp.Compare(str); |
||||||
|
if(!res) continue; |
||||||
|
if(NOTDEF!=proj) // Ambiguos string
|
||||||
|
{ |
||||||
|
err="Ambiguous projection definition: did you mean \""+t1+"\" or \""+cmp.Template2Name()+"\"?"; |
||||||
|
proj=NOTDEF; |
||||||
|
return false; |
||||||
|
} |
||||||
|
t1=cmp.Template2Name(); |
||||||
|
proj=m.second; |
||||||
|
} |
||||||
|
|
||||||
|
if(NOTDEF!=proj) return true; // All Ok
|
||||||
|
err="Unknown projection: "+s; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
static void FillProjNames(); |
||||||
|
|
||||||
|
private: |
||||||
|
static std::map<std::string,projection> projnames; |
||||||
|
}; |
||||||
|
|
||||||
|
// Color
|
||||||
|
struct gmt_color: public gmt_struct |
||||||
|
{ |
||||||
|
public: |
||||||
|
|
||||||
|
enum ColorModel {RGB,GRAY,HSV,CMYK}; |
||||||
|
ColorModel model; |
||||||
|
union |
||||||
|
{ |
||||||
|
double gray; // 0-255
|
||||||
|
struct {double r,g,b;}; // 0-255
|
||||||
|
struct {double hue,saturation,value;}; // 0-360, 0-1, 0-1
|
||||||
|
struct {double cyan,magenta,yellow,black;}; // 0-100
|
||||||
|
}; |
||||||
|
double transparency; |
||||||
|
std::string Value() const |
||||||
|
{ |
||||||
|
std::string trans=(transparency!=0)?("@"+ToString(transparency)):""; |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return ToString(r)+"/"+ToString(g)+"/"+ToString(b)+trans; |
||||||
|
case(GRAY): return ToString(gray)+trans; |
||||||
|
case(HSV): return ToString(hue)+"-"+ToString(saturation)+"-"+ToString(value)+trans; |
||||||
|
case(CMYK): return ToString(cyan)+"/"+ToString(magenta)+"/"+ToString(yellow)+"/"+ToString(black)+trans; |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
double Gray() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2Gray().gray; |
||||||
|
case(GRAY): return gray; |
||||||
|
case(HSV): return HSV2Gray().gray; |
||||||
|
case(CMYK): return CMYK2Gray().gray; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
void ToGray() |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): gray=RGB2Gray().gray; break; |
||||||
|
case(GRAY): return; |
||||||
|
case(HSV): gray=HSV2Gray().gray; break; |
||||||
|
case(CMYK): gray=CMYK2Gray().gray; break; |
||||||
|
} |
||||||
|
model=GRAY; |
||||||
|
} |
||||||
|
|
||||||
|
double R() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return r; |
||||||
|
case(GRAY): return Gray2RGB().r; |
||||||
|
case(HSV): return HSV2RGB().r; |
||||||
|
case(CMYK): return CMYK2RGB().r; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double G() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return g; |
||||||
|
case(GRAY): return Gray2RGB().g; |
||||||
|
case(HSV): return HSV2RGB().g; |
||||||
|
case(CMYK): return CMYK2RGB().g; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double B() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return b; |
||||||
|
case(GRAY): return Gray2RGB().b; |
||||||
|
case(HSV): return HSV2RGB().b; |
||||||
|
case(CMYK): return CMYK2RGB().b; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
void ToRGB() |
||||||
|
{ |
||||||
|
gmt_color c; |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return; |
||||||
|
case(GRAY): c=Gray2RGB(); break; |
||||||
|
case(HSV): c=HSV2RGB(); break; |
||||||
|
case(CMYK): c=CMYK2RGB(); break; |
||||||
|
} |
||||||
|
model=RGB; |
||||||
|
r=c.r; g=c.g; b=c.b; |
||||||
|
} |
||||||
|
|
||||||
|
double H() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2HSV().hue; |
||||||
|
case(GRAY): return Gray2HSV().hue; |
||||||
|
case(HSV): return hue; |
||||||
|
case(CMYK): return CMYK2HSV().hue; |
||||||
|
} |
||||||
|
return 0;// Own functions
|
||||||
|
} |
||||||
|
double S() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2HSV().saturation; |
||||||
|
case(GRAY): return Gray2HSV().saturation; |
||||||
|
case(HSV): return saturation; |
||||||
|
case(CMYK): return CMYK2HSV().saturation; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double V() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2HSV().value; |
||||||
|
case(GRAY): return Gray2HSV().value; |
||||||
|
case(HSV): return value; |
||||||
|
case(CMYK): return CMYK2HSV().value; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
void ToHSV() |
||||||
|
{ |
||||||
|
gmt_color c; |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): c=RGB2HSV(); break; |
||||||
|
case(GRAY): c=Gray2HSV(); break; |
||||||
|
case(HSV): return; |
||||||
|
case(CMYK): c=CMYK2HSV(); break; |
||||||
|
} |
||||||
|
model=HSV; |
||||||
|
hue=c.hue; saturation=c.saturation; value=c.value; |
||||||
|
} |
||||||
|
|
||||||
|
double C() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2CMYK().cyan; |
||||||
|
case(GRAY): return Gray2CMYK().cyan; |
||||||
|
case(HSV): return HSV2CMYK().cyan; |
||||||
|
case(CMYK): return cyan; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double M() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2CMYK().magenta; |
||||||
|
case(GRAY): return Gray2CMYK().magenta; |
||||||
|
case(HSV): return HSV2CMYK().magenta; |
||||||
|
case(CMYK): return magenta; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double Y() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2CMYK().yellow; |
||||||
|
case(GRAY): return Gray2CMYK().yellow; |
||||||
|
case(HSV): return HSV2CMYK().yellow; |
||||||
|
case(CMYK): return yellow; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
double K() const |
||||||
|
{ |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): return RGB2CMYK().black; |
||||||
|
case(GRAY): return Gray2CMYK().black; |
||||||
|
case(HSV): return HSV2CMYK().black; |
||||||
|
case(CMYK): return black; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
void ToCMYK() |
||||||
|
{ |
||||||
|
gmt_color cc; |
||||||
|
switch(model) |
||||||
|
{ |
||||||
|
case(RGB): cc=RGB2CMYK(); break; |
||||||
|
case(GRAY): cc=Gray2CMYK(); break; |
||||||
|
case(HSV): cc=HSV2CMYK(); break; |
||||||
|
case(CMYK): return; |
||||||
|
} |
||||||
|
model=CMYK; |
||||||
|
cyan=cc.cyan; magenta=cc.magenta; yellow=cc.yellow; black=cc.black; |
||||||
|
} |
||||||
|
|
||||||
|
void ToModel(ColorModel newmodel) |
||||||
|
{ |
||||||
|
switch(newmodel) |
||||||
|
{ |
||||||
|
case(RGB): ToRGB(); return; |
||||||
|
case(GRAY): ToGray(); return; |
||||||
|
case(HSV): ToHSV(); return; |
||||||
|
case(CMYK): ToCMYK(); return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Interpret one numeric argument as gray value
|
||||||
|
bool Convert(double gr, std::string& err) |
||||||
|
{ |
||||||
|
Value2RGB g(gr); |
||||||
|
bool suc=true; |
||||||
|
model=GRAY; |
||||||
|
transparency=0.0; |
||||||
|
gray=g(&suc,err); |
||||||
|
return suc; |
||||||
|
} |
||||||
|
|
||||||
|
bool Convert(const std::string& istr, std::string& err) |
||||||
|
{ |
||||||
|
std::string cstr=istr; |
||||||
|
tolower(cstr); |
||||||
|
|
||||||
|
transparency=0.0; |
||||||
|
// Transparency check
|
||||||
|
{ |
||||||
|
WordList wl=Split(cstr,"@"); |
||||||
|
if(1!=wl.size() && 2!=wl.size()) return false; |
||||||
|
if(2==wl.size()) |
||||||
|
{ |
||||||
|
WordList::const_iterator ci=wl.begin(); |
||||||
|
bool suc=true; |
||||||
|
cstr=*ci; |
||||||
|
ci++; |
||||||
|
Value2Transp t(*ci); |
||||||
|
transparency=t(&suc,err); |
||||||
|
if(!suc) return false; // Parse error
|
||||||
|
} |
||||||
|
} |
||||||
|
{ |
||||||
|
WordList wl_slash=Split(cstr,"/"),wl_hyphen=Split(cstr,"-"); |
||||||
|
WordList::size_type slash_size=wl_slash.size(),hyphen_size=wl_hyphen.size(); |
||||||
|
// Checks
|
||||||
|
if(slash_size>1 && hyphen_size>1) {err="Delimeter of color components must be \"/\" or \"-\", not both"; return false;} |
||||||
|
if(2==slash_size || slash_size>4) {err="Number of color components must be 1 for GRAY, 3 for RGB or 4 for CMYK"; return false;} |
||||||
|
if(2==hyphen_size || hyphen_size>3) {err="There is 3 color components in HSV model"; return false;} |
||||||
|
// Gray or name
|
||||||
|
// TODO: Hex representation
|
||||||
|
if(1==slash_size && 1==hyphen_size) |
||||||
|
{ |
||||||
|
if(SetByName(cstr)) return true; // Set color by name, all ok
|
||||||
|
Value2RGB g(cstr); |
||||||
|
bool suc=true; |
||||||
|
model=GRAY; |
||||||
|
gray=g(&suc,err); |
||||||
|
err="Can't understand string "+cstr+", this is nor color name, nor gray value (0-255)"; |
||||||
|
return suc; |
||||||
|
} |
||||||
|
// RGB
|
||||||
|
if(3==slash_size) |
||||||
|
{ |
||||||
|
Value2RGB red(wl_slash.front()); wl_slash.pop_front(); |
||||||
|
Value2RGB green(wl_slash.front()); wl_slash.pop_front(); |
||||||
|
Value2RGB blue(wl_slash.front()); |
||||||
|
bool suc=true; |
||||||
|
model=RGB; |
||||||
|
r=red(&suc,err); if(!suc) return suc; |
||||||
|
g=green(&suc,err);if(!suc) return suc; |
||||||
|
b=blue(&suc,err); |
||||||
|
return suc; |
||||||
|
} |
||||||
|
// HSV
|
||||||
|
if(3==hyphen_size) |
||||||
|
{ |
||||||
|
Value2Hue h(wl_hyphen.front()); wl_hyphen.pop_front(); |
||||||
|
Value2SV s(wl_hyphen.front()); wl_hyphen.pop_front(); |
||||||
|
Value2SV v(wl_hyphen.front()); |
||||||
|
bool suc=true; |
||||||
|
model=HSV; |
||||||
|
hue=h(&suc,err); if(!suc) return suc; |
||||||
|
saturation=s(&suc,err);if(!suc) return suc; |
||||||
|
value=v(&suc,err); |
||||||
|
return suc; |
||||||
|
} |
||||||
|
// CMYK
|
||||||
|
if(4==slash_size) |
||||||
|
{ |
||||||
|
Value2CMYK c(wl_slash.front()); wl_slash.pop_front(); |
||||||
|
Value2CMYK m(wl_slash.front()); wl_slash.pop_front(); |
||||||
|
Value2CMYK y(wl_slash.front()); wl_slash.pop_front(); |
||||||
|
Value2CMYK k(wl_slash.front()); |
||||||
|
bool suc=true; |
||||||
|
model=CMYK; |
||||||
|
cyan=c(&suc,err); if(!suc) return suc; |
||||||
|
magenta=m(&suc,err);if(!suc) return suc; |
||||||
|
yellow=y(&suc,err); if(!suc) return suc; |
||||||
|
black=k(&suc,err); |
||||||
|
return suc; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool SetByName(const std::string& name) |
||||||
|
{ |
||||||
|
const struct colorname* cdata; |
||||||
|
model=RGB; |
||||||
|
cdata=ColorHash::in_colors_set(name.c_str(),name.length()); |
||||||
|
if(0==cdata) return false; |
||||||
|
r=cdata->r; |
||||||
|
g=cdata->g; |
||||||
|
b=cdata->b; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Transformation functions
|
||||||
|
private: |
||||||
|
#include "modgmt_colortransform.h" |
||||||
|
}; |
||||||
|
|
||||||
|
// Dash
|
||||||
|
struct gmt_dash: public gmt_struct |
||||||
|
{ |
||||||
|
std::vector<double> dash; |
||||||
|
double shift; |
||||||
|
double width; |
||||||
|
bool wisrel; |
||||||
|
static const double default_width; |
||||||
|
std::string Value() const |
||||||
|
{ |
||||||
|
std::string ret; |
||||||
|
if(dash.empty()) return ret; |
||||||
|
for(auto i:dash) ret+=ToString((wisrel?width:1.0)*i/10.0)+"_"; |
||||||
|
ret.back()=':'; |
||||||
|
ret+=ToString(shift)+"c"; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
operator bool() const {return !dash.empty();} |
||||||
|
void Clear() {dash.clear(); shift=0.0; wisrel=false;} |
||||||
|
|
||||||
|
bool Convert(const std::string& in, std::string& err, double w=0.0) |
||||||
|
{ |
||||||
|
Clear(); |
||||||
|
shift=0; |
||||||
|
if(0==in.size()) return true; // No dash
|
||||||
|
if(std::string::npos==in.find_first_not_of(".-")) // dot-dash form
|
||||||
|
{ |
||||||
|
width=(0==w)?default_width:w; |
||||||
|
wisrel=true; |
||||||
|
for(const auto& i:in) |
||||||
|
{ |
||||||
|
if('.'==i) dash.push_back(1); // Dot
|
||||||
|
else dash.push_back(8); // Dash
|
||||||
|
dash.push_back(4); // Gap
|
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
std::string dstr=in; |
||||||
|
// Determine shift
|
||||||
|
{ |
||||||
|
WordList wl=Split(in,":"); |
||||||
|
if(wl.size()>2) {err="Incorrect dash format"; return false;} |
||||||
|
if(2==wl.size()) |
||||||
|
{ |
||||||
|
Value2Width s(wl.back()); |
||||||
|
bool suc=true; |
||||||
|
shift=s(&suc,err); |
||||||
|
if(!suc) return false; // Parse error
|
||||||
|
dstr=wl.front(); |
||||||
|
} |
||||||
|
} |
||||||
|
WordList wl=Split(dstr,"_"); |
||||||
|
for(const auto& i:wl) |
||||||
|
{ |
||||||
|
Value2Width d(i); |
||||||
|
bool suc=true; |
||||||
|
dash.push_back(d(&suc,err)); |
||||||
|
if(!suc) return false; // Parse error
|
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Pen
|
||||||
|
struct gmt_pen: public gmt_struct |
||||||
|
{ |
||||||
|
double width; |
||||||
|
struct gmt_color color; |
||||||
|
struct gmt_dash dash; |
||||||
|
static const double default_width; |
||||||
|
std::string Value() const {return ToString(width/10.0)+"c,"+color.Value()+(dash?(","+dash.Value()):"");} |
||||||
|
|
||||||
|
// Interpret one numeric argument as width value
|
||||||
|
bool Convert(double in, std::string& err) |
||||||
|
{ |
||||||
|
Value2Width w(in); |
||||||
|
bool suc=true; |
||||||
|
color.Convert(0,err); // Black
|
||||||
|
dash.Clear(); |
||||||
|
width=w(&suc,err); |
||||||
|
return suc; |
||||||
|
} |
||||||
|
|
||||||
|
// Convert from string
|
||||||
|
bool Convert(const std::string& istr, std::string& err) |
||||||
|
{ |
||||||
|
std::string str=istr; |
||||||
|
WordList::const_iterator ci; |
||||||
|
tolower(str); |
||||||
|
WordList wl=Split(str,",",true); |
||||||
|
|
||||||
|
// Defaults
|
||||||
|
width=default_width; |
||||||
|
color.Convert(0,err); // Black
|
||||||
|
dash.Clear(); |
||||||
|
|
||||||
|
if(wl.size()>3) return false; // String is [width][,color][,dash]
|
||||||
|
ci=wl.begin(); |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
Value2Width w(*ci); |
||||||
|
bool suc=true; |
||||||
|
width=w(&suc,err); |
||||||
|
if(!suc) return false; // Parse error
|
||||||
|
} |
||||||
|
if(wl.end()!=ci) ci++; |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
if(!color.Convert(*ci,err)) return false; // Parse error
|
||||||
|
} |
||||||
|
if(wl.end()!=ci) ci++; |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
if(!dash.Convert(*ci,err,width)) return false; // Parse error
|
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Font
|
||||||
|
struct gmt_font: public gmt_struct |
||||||
|
{ |
||||||
|
double size; |
||||||
|
struct gmt_color color; |
||||||
|
std::string family; |
||||||
|
static std::string default_family; |
||||||
|
static std::set<std::string> families; |
||||||
|
static const double default_size; |
||||||
|
|
||||||
|
std::string Value() const {return ToString(size)+"p,"+family+","+color.Value();} |
||||||
|
|
||||||
|
// Interpret one numeric argument as size of default black font
|
||||||
|
bool Convert(double in, std::string& err) |
||||||
|
{ |
||||||
|
Value2Width s(in); |
||||||
|
bool suc=true; |
||||||
|
color.Convert(0,err); // Black
|
||||||
|
size=s(&suc,err); |
||||||
|
family=default_family; |
||||||
|
return suc; |
||||||
|
} |
||||||
|
|
||||||
|
// Convert from string
|
||||||
|
bool Convert(const std::string& str, std::string& err) |
||||||
|
{ |
||||||
|
WordList::const_iterator ci; |
||||||
|
WordList wl=Split(str,",",true); |
||||||
|
std::string fakeerr; |
||||||
|
|
||||||
|
// Defaults
|
||||||
|
size=default_size; |
||||||
|
family=default_family; |
||||||
|
color.Convert(0,fakeerr); // Black
|
||||||
|
|
||||||
|
if(wl.size()>3) {err="String "+str+" is not font string"; return false;} // String is [size][,family][,color] or [family][,color]
|
||||||
|
ci=wl.begin(); |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
Value2Width s(*ci); |
||||||
|
bool suc=true; |
||||||
|
{ |
||||||
|
std::string fake; |
||||||
|
double newsize=s(&suc,fake); |
||||||
|
if(suc) size=newsize; |
||||||
|
} |
||||||
|
if(!suc) // Parse error. check if argument is font name
|
||||||
|
{ |
||||||
|
if(0==families.count(*ci)) return false; // No, argument is not allowed font name
|
||||||
|
family=*ci; |
||||||
|
if(wl.size()>2) {err="String "+str+" is not font string"; return false;} // If first word is font name, then words count is 1 or 2.
|
||||||
|
goto read_color; |
||||||
|
} |
||||||
|
} |
||||||
|
if(wl.end()!=ci) ci++; |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
if(0==families.count(*ci)) {err="Unknown font family: "+(*ci); return false;} // Argument is not allowed font name
|
||||||
|
family=*ci; |
||||||
|
} |
||||||
|
read_color: |
||||||
|
if(wl.end()!=ci) ci++; |
||||||
|
if(wl.end()!=ci && 0!=ci->size()) |
||||||
|
{ |
||||||
|
if(!color.Convert(*ci,err)) return false; // Parse error
|
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static bool FillFontNames(); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// Layer
|
||||||
|
struct gmt_layer: public gmt_struct |
||||||
|
{ |
||||||
|
double shiftx,shifty; |
||||||
|
struct gmt_projection proj; |
||||||
|
std::string creator; |
||||||
|
std::shared_ptr<std::string> data; |
||||||
|
|
||||||
|
std::string Value() const {return creator+(Shifted()?("("+ToString(shiftx)+"x"+ToString(shifty)+")"):"");} |
||||||
|
bool Shifted() const {return shiftx!=0.0 || shifty!=0.0;} |
||||||
|
std::string BeginShift() const {return (Shifted()?("V "+ToString(cm2GMT(shiftx))+" "+ToString(cm2GMT(shifty))+" T\n"):"");} |
||||||
|
std::string EndShift() const {return (Shifted()?"U\n":"");} |
||||||
|
}; |
||||||
|
#endif |
@ -0,0 +1,43 @@ |
|||||||
|
cmake_minimum_required(VERSION 2.8.5) |
||||||
|
|
||||||
|
set(EXENAME makemap) |
||||||
|
|
||||||
|
find_package(FLEX REQUIRED) |
||||||
|
find_package(BISON REQUIRED) |
||||||
|
|
||||||
|
find_library(dl dl) |
||||||
|
find_library(pthread pthread) |
||||||
|
|
||||||
|
if(NOT dl) |
||||||
|
message(FATAL_ERROR "libdl not found!") |
||||||
|
endif() |
||||||
|
|
||||||
|
if(NOT pthread) |
||||||
|
message(FATAL_ERROR "libpthread not found!") |
||||||
|
endif() |
||||||
|
|
||||||
|
file(GLOB srcs *.cpp) |
||||||
|
BISON_TARGET(GParser parser/grammatical.y ${CMAKE_CURRENT_BINARY_DIR}/grammatical.cpp) |
||||||
|
FLEX_TARGET(LScanner parser/lexical.l ${CMAKE_CURRENT_BINARY_DIR}/lexical.cpp COMPILE_FLAGS "--header-file=${CMAKE_CURRENT_BINARY_DIR}/lexical.h") |
||||||
|
set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES lexical.h) |
||||||
|
|
||||||
|
set(MODULES_SOURCES "") |
||||||
|
set(MODULES_LIBS "") |
||||||
|
|
||||||
|
foreach(moddir ${STATIC_MODULES}) |
||||||
|
include(${moddir}/ModuleSetup.cmake OPTIONAL) |
||||||
|
file(GLOB modsrcs ${moddir}/*.cpp) |
||||||
|
set(MODULES_SOURCES ${MODULES_SOURCES} ${modsrcs} ${MODULE_ADDITIONAL_SOURCES}) |
||||||
|
set(MODULES_LIBS ${MODULES_LIBS} ${MODULE_ADDITIONAL_LIBRARIES}) |
||||||
|
include_directories(${MODULE_ADDITIONAL_INCLUDES}) |
||||||
|
endforeach() |
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
||||||
|
add_executable(${EXENAME} ${srcs} ${FLEX_LScanner_OUTPUTS} ${BISON_GParser_OUTPUTS} ${MODULES_SOURCES}) |
||||||
|
|
||||||
|
# Workaround. BISON_TARGET makes header with extension .hpp, but we use extension .h |
||||||
|
set_source_files_properties(init.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/grammatical.h) |
||||||
|
add_custom_command(OUTPUT grammatical.h COMMAND cp grammatical.hpp grammatical.h DEPENDS grammatical.hpp WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) |
||||||
|
|
||||||
|
target_link_libraries(${EXENAME} ${linker_options} ${dl} ${pthread} ${MODULES_LIBS}) |
||||||
|
set_target_properties(${EXENAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) |
@ -1,155 +0,0 @@ |
|||||||
#include <math.h> |
|
||||||
#include "object.h" |
|
||||||
|
|
||||||
ObjectBase* Arifm_Add(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=2) return 0; |
|
||||||
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
|
||||||
std::type_index t1(typeid(*arg1)),t2(typeid(*arg2)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
if( (t1!=tr && t1!=ti) || (t2!=tr && t2!=ti) ) return 0; |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t1==ti && t2==ti) return new ObjectInt(dynamic_cast<const ObjectInt*>(arg1)->Value() + dynamic_cast<const ObjectInt*>(arg2)->Value()); |
|
||||||
|
|
||||||
// Real arifmetic
|
|
||||||
double r1,r2; |
|
||||||
|
|
||||||
if(t1==tr) r1=dynamic_cast<const ObjectReal*>(arg1)->Value(); |
|
||||||
else r1=dynamic_cast<const ObjectInt*>(arg1)->Value(); |
|
||||||
|
|
||||||
if(t2==tr) r2=dynamic_cast<const ObjectReal*>(arg2)->Value(); |
|
||||||
else r2=dynamic_cast<const ObjectInt*>(arg2)->Value(); |
|
||||||
|
|
||||||
return new ObjectReal(r1+r2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Sub(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=2) return 0; |
|
||||||
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
|
||||||
std::type_index t1(typeid(*arg1)),t2(typeid(*arg2)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
if( (t1!=tr && t1!=ti) || (t2!=tr && t2!=ti) ) return 0; |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t1==ti && t2==ti) return new ObjectInt(dynamic_cast<const ObjectInt*>(arg1)->Value() - dynamic_cast<const ObjectInt*>(arg2)->Value()); |
|
||||||
|
|
||||||
// Real arifmetic
|
|
||||||
double r1,r2; |
|
||||||
|
|
||||||
if(t1==tr) r1=dynamic_cast<const ObjectReal*>(arg1)->Value(); |
|
||||||
else r1=dynamic_cast<const ObjectInt*>(arg1)->Value(); |
|
||||||
|
|
||||||
if(t2==tr) r2=dynamic_cast<const ObjectReal*>(arg2)->Value(); |
|
||||||
else r2=dynamic_cast<const ObjectInt*>(arg2)->Value(); |
|
||||||
|
|
||||||
return new ObjectReal(r1-r2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Mul(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=2) return 0; |
|
||||||
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
|
||||||
std::type_index t1(typeid(*arg1)),t2(typeid(*arg2)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
if( (t1!=tr && t1!=ti) || (t2!=tr && t2!=ti) ) return 0; |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t1==ti && t2==ti) return new ObjectInt(dynamic_cast<const ObjectInt*>(arg1)->Value() * dynamic_cast<const ObjectInt*>(arg2)->Value()); |
|
||||||
|
|
||||||
// Real arifmetic
|
|
||||||
double r1,r2; |
|
||||||
|
|
||||||
if(t1==tr) r1=dynamic_cast<const ObjectReal*>(arg1)->Value(); |
|
||||||
else r1=dynamic_cast<const ObjectInt*>(arg1)->Value(); |
|
||||||
|
|
||||||
if(t2==tr) r2=dynamic_cast<const ObjectReal*>(arg2)->Value(); |
|
||||||
else r2=dynamic_cast<const ObjectInt*>(arg2)->Value(); |
|
||||||
|
|
||||||
return new ObjectReal(r1*r2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Div(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=2) return 0; |
|
||||||
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
|
||||||
std::type_index t1(typeid(*arg1)),t2(typeid(*arg2)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
if( (t1!=tr && t1!=ti) || (t2!=tr && t2!=ti) ) return 0; |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t1==ti && t2==ti) return new ObjectInt(dynamic_cast<const ObjectInt*>(arg1)->Value() / dynamic_cast<const ObjectInt*>(arg2)->Value()); |
|
||||||
|
|
||||||
// Real arifmetic
|
|
||||||
double r1,r2; |
|
||||||
|
|
||||||
if(t1==tr) r1=dynamic_cast<const ObjectReal*>(arg1)->Value(); |
|
||||||
else r1=dynamic_cast<const ObjectInt*>(arg1)->Value(); |
|
||||||
|
|
||||||
if(t2==tr) r2=dynamic_cast<const ObjectReal*>(arg2)->Value(); |
|
||||||
else r2=dynamic_cast<const ObjectInt*>(arg2)->Value(); |
|
||||||
|
|
||||||
return new ObjectReal(r1/r2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Pow(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=2) return 0; |
|
||||||
const ObjectBase *arg1=input->At(0),*arg2=input->At(1); |
|
||||||
std::type_index t1(typeid(*arg1)),t2(typeid(*arg2)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
if( (t1!=tr && t1!=ti) || (t2!=tr && t2!=ti) ) return 0; |
|
||||||
|
|
||||||
// Only real arifmetic
|
|
||||||
double r1,r2; |
|
||||||
|
|
||||||
if(t1==tr) r1=dynamic_cast<const ObjectReal*>(arg1)->Value(); |
|
||||||
else r1=dynamic_cast<const ObjectInt*>(arg1)->Value(); |
|
||||||
|
|
||||||
if(t2==tr) r2=dynamic_cast<const ObjectReal*>(arg2)->Value(); |
|
||||||
else r2=dynamic_cast<const ObjectInt*>(arg2)->Value(); |
|
||||||
|
|
||||||
return new ObjectReal(pow(r1,r2)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Neg(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=1) return 0; |
|
||||||
const ObjectBase *arg=input->At(0); |
|
||||||
std::type_index t(typeid(*arg)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t==ti) return new ObjectInt(-dynamic_cast<const ObjectInt*>(arg)->Value()); |
|
||||||
// Real arifmetic
|
|
||||||
if(t==tr) return new ObjectReal(-dynamic_cast<const ObjectReal*>(arg)->Value()); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ObjectBase* Arifm_Pos(const ObjectList* input) |
|
||||||
{ |
|
||||||
if(input->Size()!=1) return 0; |
|
||||||
const ObjectBase *arg=input->At(0); |
|
||||||
std::type_index t(typeid(*arg)); |
|
||||||
std::type_index tr(typeid(ObjectReal)),ti(typeid(ObjectInt)); |
|
||||||
|
|
||||||
// Integer arifmetic
|
|
||||||
if(t==ti) return new ObjectInt(dynamic_cast<const ObjectInt*>(arg)->Value()); |
|
||||||
// Real arifmetic
|
|
||||||
if(t==tr) return new ObjectReal(dynamic_cast<const ObjectReal*>(arg)->Value()); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
SHELL=/bin/bash
|
|
||||||
OPTFLAGS=-O2 -flto -g
|
|
||||||
EXPORTFLAGS=-fvisibility=hidden -fpic -Wl,--export-dynamic
|
|
||||||
CPPFLAGS=-std=gnu++11 -I../include -I/home/michael/tmp/gmt5/include/gmt
|
|
||||||
LIBSFLAGS=-L/home/michael/tmp/gmt5/lib64 -Wl,-rpath /home/michael/tmp/gmt5/lib64 -lgmt -ldl -lpthread $(MODLIBS)
|
|
||||||
WARNFLAGS=-Wall
|
|
||||||
|
|
||||||
CFLAGS=$(OPTFLAGS) $(EXPORTFLAGS) $(WARNFLAGS) $(CPPFLAGS)
|
|
||||||
LDFLAGS=$(OPTFLAGS) $(EXPORTFLAGS) $(WARNFLAGS) $(LIBSFLAGS)
|
|
||||||
|
|
||||||
CC=g++
|
|
||||||
|
|
||||||
SOURCE = $(wildcard *.cpp)
|
|
||||||
DEPENDS = $(subst .cpp,.d,$(SOURCE))
|
|
||||||
OBJECTS = $(subst .cpp,.o,$(SOURCE))
|
|
||||||
|
|
||||||
gmttest: $(OBJECTS) $(MODOBJECTS) |
|
||||||
$(CC) -o $@ $(OBJECTS) $(MODOBJECTS) $(LDFLAGS)
|
|
||||||
|
|
||||||
include $(DEPENDS) |
|
||||||
|
|
||||||
%.o: %.cpp |
|
||||||
$(CC) -c $(CFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
%.d: %.cpp |
|
||||||
$(CC) $(CPPFLAGS) -MM -MT $(subst .cpp,.o,$<) $< | sed 's%\(^.*\):%\1 $@ :%g' >$@
|
|
||||||
|
|
||||||
clean: |
|
||||||
rm -f *.o *.d
|
|
||||||
|
|
||||||
distclean: clean |
|
||||||
rm -f gmttest
|
|
@ -1,99 +0,0 @@ |
|||||||
#include <gmt.h> |
|
||||||
#include <iostream> |
|
||||||
#include <string> |
|
||||||
#include <unistd.h> |
|
||||||
#include <sys/wait.h> |
|
||||||
|
|
||||||
int print_func(FILE* fd, const char* str) |
|
||||||
{ |
|
||||||
std::cout<<"PRINT: "<<str<<std::endl; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
struct gmtworkthreadpars |
|
||||||
{ |
|
||||||
void* api; |
|
||||||
const char* module; |
|
||||||
struct GMT_OPTION* opts; |
|
||||||
int fd; |
|
||||||
int ret; |
|
||||||
}; |
|
||||||
|
|
||||||
void gmtonexithandler(int ret, void* x) |
|
||||||
{ |
|
||||||
reinterpret_cast<struct gmtworkthreadpars*>(x)->ret=ret; |
|
||||||
close(reinterpret_cast<struct gmtworkthreadpars*>(x)->fd); |
|
||||||
pthread_exit(&(reinterpret_cast<struct gmtworkthreadpars*>(x)->ret)); |
|
||||||
} |
|
||||||
|
|
||||||
void* gmtworkthread(void* x) |
|
||||||
{ |
|
||||||
struct gmtworkthreadpars* p=reinterpret_cast<struct gmtworkthreadpars*>(x); |
|
||||||
on_exit(gmtonexithandler,x); |
|
||||||
GMT_Append_Option(p->api,GMT_Make_Option(p->api,'>',const_cast<char*>(("/dev/fd/"+std::to_string(p->fd)).c_str())),p->opts); |
|
||||||
p->ret=GMT_Call_Module(p->api,p->module,GMT_MODULE_OPT,p->opts); |
|
||||||
exit(p->ret); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int callgmtmodule(void *api, const char *module, struct GMT_OPTION *opts, std::string& res) |
|
||||||
{ |
|
||||||
int pipefd[2]; |
|
||||||
ssize_t br; |
|
||||||
char buffer[4096]; |
|
||||||
pthread_t wthr; |
|
||||||
struct gmtworkthreadpars p; |
|
||||||
int *pret; |
|
||||||
|
|
||||||
pipe(pipefd); |
|
||||||
p.api=api; |
|
||||||
p.module=module; |
|
||||||
p.opts=opts; |
|
||||||
p.fd=pipefd[1]; |
|
||||||
|
|
||||||
pthread_create(&wthr,0,&gmtworkthread,&p); |
|
||||||
|
|
||||||
res.erase(); |
|
||||||
//read(pipefd[0],buffer,1);
|
|
||||||
//close(pipefd[1]);
|
|
||||||
do |
|
||||||
{ |
|
||||||
br=read(pipefd[0],buffer,4096); |
|
||||||
std::cout<<res.length()<<" "<<br<<std::endl; |
|
||||||
res.append(buffer,br); |
|
||||||
} while(0!=br); |
|
||||||
close(pipefd[0]); |
|
||||||
res.shrink_to_fit(); |
|
||||||
pthread_join(wthr,reinterpret_cast<void**>(&pret)); |
|
||||||
|
|
||||||
return *pret; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
int main() |
|
||||||
{ |
|
||||||
char* text="GMT"; |
|
||||||
//void* out;
|
|
||||||
void* gmtapi; |
|
||||||
std::string args="-R130/160/40/60 -JM12c -Xa2c -Ya2c -B5/5/swNE --GMT_HISTORY=f --FONT_ANNOT_PRIMARY=14p,Times-Bold,red"; |
|
||||||
struct GMT_OPTION* opts; |
|
||||||
int io,ret; |
|
||||||
char fname[16]; |
|
||||||
std::string out; |
|
||||||
|
|
||||||
gmtapi=GMT_Create_Session(text,2,3,print_func); |
|
||||||
io=GMT_Register_IO(gmtapi,GMT_IS_TEXTSET,GMT_IS_DUPLICATE,GMT_IS_NONE,GMT_OUT,0,0); |
|
||||||
GMT_Encode_ID(gmtapi,fname,io); |
|
||||||
opts=GMT_Create_Options(gmtapi,0,(void*)args.c_str()); |
|
||||||
//ret=GMT_Init_IO(gmtapi,GMT_IS_TEXTSET,GMT_IS_NONE,GMT_OUT,5,0,opts);
|
|
||||||
std::cout<<io<<" "<<GMT_NOTSET<<" "<<fname<<" "<<ret<<std::endl; |
|
||||||
|
|
||||||
ret=callgmtmodule(gmtapi,"psbasemap",opts,out); |
|
||||||
std::cout<<"Return value: "<<ret<<std::endl; |
|
||||||
std::cout<<out.max_size()<<" "<<out.capacity()<<" "<<out.size()<<std::endl; |
|
||||||
|
|
||||||
GMT_Destroy_Options(gmtapi,&opts); |
|
||||||
GMT_Destroy_Session(gmtapi); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
@ -0,0 +1,11 @@ |
|||||||
|
# Description: Coord tests. Must passed. |
||||||
|
# Status: ok |
||||||
|
# Output hash: 1a1ca4aba24d0fe39407eef250167aca5c21373722f5f2a9bd6495cee34abaf2 |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
a=Coord("10:30:18"); |
||||||
|
b=Coord(10.5); |
||||||
|
c=Coord(":10:10"); |
||||||
|
d=Coord("-0:15:18"); |
||||||
|
|
||||||
|
print(a,a.n,b,b.n,c,c.n,d,d.n); |
@ -0,0 +1,8 @@ |
|||||||
|
# Description: Non-integer degrees in dd:mm:ss mode. |
||||||
|
# Status: fail |
||||||
|
# Output hash: 9469953f706df02349e019f8b47a499d169113b654aee46cacb966d01a27848c |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
a=Coord("1.0:10"); |
||||||
|
|
||||||
|
print(a); |
@ -0,0 +1,18 @@ |
|||||||
|
# Description: Projections test |
||||||
|
# Status: ok |
||||||
|
# Output hash: 18656de8c59c9a218b71dc730a3a1e8f1016179622392b11f052c64210f6fa2d |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
r=Region("130",150,30,50); |
||||||
|
|
||||||
|
px=Projection("dec",10,(10,20,10,20),15); |
||||||
|
p=Projection(r,type="cyl equid",h=10,stpar=0); |
||||||
|
p1=Projection(p,type="m",w=10); |
||||||
|
p2b=Projection("ob",10,r,"eq",(r.xe.n+r.xb.n)/2,(r.ye.n+r.yb.n)/2,140,15); |
||||||
|
p2=Projection(p2b,he=10); |
||||||
|
p3=Projection("cas",11,r); |
||||||
|
p4=Projection(r,type="cequa",11); |
||||||
|
p5=Projection(p4,type="j",centralm="130:30"); |
||||||
|
p6=Projection("cylstereo",10,r); |
||||||
|
|
||||||
|
print(px,p,p1,p2,p3,p4,p5,p6); |
@ -0,0 +1,10 @@ |
|||||||
|
# Description: Global regions test. |
||||||
|
# Status: ok |
||||||
|
# Output hash: e661246caef9b2a5fa5a96b9d75c0542d2e0e655de9d63d755aff01cd3b4ceba |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
r1=Region("global"); |
||||||
|
r2=Region("global360"); |
||||||
|
r3=Region("global180"); |
||||||
|
|
||||||
|
print(r1,r1.xb,r1.xe,r2,r2.xb,r2.xe,r3,r3.xb,r3.xe); |
@ -0,0 +1,9 @@ |
|||||||
|
# Description: Test sequential form of Region. |
||||||
|
# Status: ok |
||||||
|
# Output hash: a8006abe2c42b9e34c692ab88cf2f869ad6a01d1f32e6da842c1320f0d253d1c |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
r1=Region("10:30",20.5,-10.5,100,"bbox"); |
||||||
|
r2=Region("10:30",-10.5,20.5,100); |
||||||
|
|
||||||
|
print(r1,r2,r1.yb,r2.yb); |
@ -0,0 +1,13 @@ |
|||||||
|
# Description: Check named pairs form of Region. |
||||||
|
# Status: ok |
||||||
|
# Output hash: cf4acbeb2da3156fe52f1f374d4dc83a1aa0ee129a8aa2b1975ec828dd23cabe |
||||||
|
@use "gmt" |
||||||
|
|
||||||
|
r=Region("10:30",-10.5,20.5,100); |
||||||
|
r1=Region(r,type="bbox"); |
||||||
|
r2=Region(r,type="global180"); |
||||||
|
r3=Region(r,ye=80.5); |
||||||
|
l=(xb=r.xb.n-0.5,(xe=20+r.xb.n-10,yb=-10),(ye="11:30:28")); |
||||||
|
rr=Region(l, type="bbox"); |
||||||
|
|
||||||
|
print(r,r1,r2,r3,rr); |
Loading…
Reference in new issue