|
|
|
#include <pthread.h>
|
|
|
|
#include "common.h"
|
|
|
|
#include "modgmt_internals.h"
|
|
|
|
|
|
|
|
std::string header,footer;
|
|
|
|
std::string datadir;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
pipe(pipefd);
|
|
|
|
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));
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|