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

#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;
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;
}