#include #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(x)->ret=ret; close(reinterpret_cast(x)->fd); pthread_exit(&(reinterpret_cast(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(x); #if defined MODGMT_WORKAROUND_EXIT on_exit(gmtonexithandler,x); #endif GMT_Append_Option(p->api,GMT_Make_Option(p->api,'>',const_cast(("/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(&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; }