Michael Uleysky
9 years ago
7 changed files with 277 additions and 16 deletions
@ -0,0 +1,223 @@
|
||||
#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; |
||||
} |
||||
|
||||
|
||||
// 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). |
||||
*/ |
||||
ObjectBase* GMT_Map(const ObjectList* input) |
||||
{ |
||||
const ObjectList* list=input; |
||||
auto size=list->Size(); |
||||
if(0==size) return 0; |
||||
decltype(size) pos=0; |
||||
std::string title; |
||||
std::stack<std::pair<const ObjectList*,decltype(pos)> > lstack; |
||||
bool first=true; |
||||
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)); |
||||
while(pos<size) |
||||
{ |
||||
// Check if next argument is list
|
||||
{ |
||||
OBType<ObjectList> l(list->At(pos)); |
||||
// Descending
|
||||
if(l) |
||||
{ |
||||
if(0==l->Size()) goto next; |
||||
lstack.push(std::make_pair(list,pos)); |
||||
list=l; |
||||
pos=0; |
||||
size=l->Size(); |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
// Check if first argument is string
|
||||
if(first) |
||||
{ |
||||
first=false; |
||||
OBType<ObjectString> s(list->At(pos)); |
||||
if(s) |
||||
{ |
||||
title=s->Value(); |
||||
goto next; |
||||
} |
||||
} |
||||
|
||||
// Check if argument is pair
|
||||
{ |
||||
OBType<ObjectPair> p(list->At(pos)); |
||||
if(p) |
||||
{ |
||||
std::string name=p->Name(); |
||||
tolower(name); |
||||
Base2Double d(p->Value()); |
||||
bool suc=true; |
||||
double val=d(&suc); |
||||
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) goto fail; // Unknown name
|
||||
goto next; |
||||
} |
||||
} |
||||
|
||||
// Check if argument is layer
|
||||
{ |
||||
OBType<ObjectGMTLayer> l(list->At(pos)); |
||||
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); |
||||
goto next; |
||||
} |
||||
} |
||||
|
||||
goto fail; // Unknown type of argument
|
||||
next: |
||||
pos++; |
||||
// Ascending
|
||||
if(pos==size && !lstack.empty()) |
||||
{ |
||||
list=lstack.top().first; |
||||
pos=lstack.top().second; |
||||
lstack.pop(); |
||||
size=list->Size(); |
||||
goto next; |
||||
} |
||||
} |
||||
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) 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()) 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) 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 0; |
||||
} |
@ -0,0 +1,34 @@
|
||||
#ifndef MODGMT_MAP_H |
||||
#define MODGMT_MAP_H |
||||
#include "common.h" |
||||
|
||||
class ObjectGMTMap: public ObjectBase |
||||
{ |
||||
std::shared_ptr<std::string> data; |
||||
int64_t bblx,bbly,bbrx,bbry; |
||||
|
||||
ObjectGMTMap(const ObjectGMTMap* p):data(p->data),bblx(p->bblx),bbly(p->bbly),bbrx(p->bbrx),bbry(p->bbry) {}; |
||||
|
||||
public: |
||||
ObjectGMTMap(std::string* s, int nbblx, int nbbly, int nbbrx, int nbbry):data(s),bblx(nbblx),bbly(nbbly),bbrx(nbbrx),bbry(nbbry) {}; |
||||
|
||||
// Pure virtual overrides
|
||||
ObjectBase* Copy() const override {return new ObjectGMTMap(this);} |
||||
bool Print() const override |
||||
{ |
||||
COUT(NORMAL)<<std::endl<<"Object type: "<<Type()<<std::endl; |
||||
return true; |
||||
} |
||||
std::string Type() const override {return "GMTMap";} |
||||
const int8_t* Blob(size_t* size) const override |
||||
{ |
||||
*size=data->size(); |
||||
return reinterpret_cast<const int8_t*>(data->data()); |
||||
} |
||||
}; |
||||
|
||||
// Creating eps map from set of layers
|
||||
ObjectBase* GMT_Map(const ObjectList* input); |
||||
|
||||
#endif |
||||
|
Loading…
Reference in new issue