You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.3 KiB
133 lines
3.3 KiB
#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; |
|
|
|
if(0!=pipe(pipefd)) {*pret=-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: |
|
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; |
|
}
|
|
|