Browse Source

Gmt module: Add function Map.

ObjPtr
Michael Uleysky 9 years ago
parent
commit
f34ab7676c
  1. 2
      modules/gmt/modgmt.cpp
  2. 10
      modules/gmt/modgmt_filter_headfoot.l
  3. 223
      modules/gmt/modgmt_map.cpp
  4. 34
      modules/gmt/modgmt_map.h
  5. 4
      modules/gmt/modgmt_objects.cpp
  6. 9
      modules/gmt/modgmt_objects.h
  7. 11
      modules/gmt/modgmt_structs.h

2
modules/gmt/modgmt.cpp

@ -2,6 +2,7 @@
#include "modgmt_func.h"
#include "modgmt_internals.h"
#include "modgmt_gsfuncs.h"
#include "modgmt_map.h"
// Initialisation function
int gmt_module_init(void* p)
@ -43,6 +44,7 @@ int gmt_module_init(void* p)
RegisterFunction("Font",GMT_Type<struct gmt_font>);
RegisterFunction("Shift",GMT_LayerShift);
RegisterFunction("DrawFrame",GMT_DrawFrame);
RegisterFunction("Map",GMT_Map);
CheckGhostscriptAbilities();
// Calculating bounding box is critical

10
modules/gmt/modgmt_filter_headfoot.l

@ -35,12 +35,12 @@
%%
<INITIAL>%%EndComments\n BEGIN(NOTCOMMENTS);
<INITIAL>%%PageTrailer\n yyextra->append(yytext,yyleng); BEGIN(ENDFOOTER);
<NOTCOMMENTS>\n%%Page:.*\n yyextra->append("\n",1);
<NOTCOMMENTS>\n%%BeginPageSetup.*\n yyextra->append("\n",1);
<NOTCOMMENTS>\n%%EndPageSetup.*\n yyextra->append("\n",1); BEGIN(ENDHEAD);
<NOTCOMMENTS>\n%%BeginSetup.*\n yyextra->append("\n",1); BEGIN(SETUP);
<NOTCOMMENTS>%%Page:.*\n
<NOTCOMMENTS>%%BeginPageSetup.*\n
<NOTCOMMENTS>%%EndPageSetup.*\n BEGIN(ENDHEAD);
<NOTCOMMENTS>%%BeginSetup.*\n BEGIN(SETUP);
<NOTCOMMENTS,ENDFOOTER>.*\n yyextra->append(yytext,yyleng);
<SETUP>\n%%EndSetup.*\n yyextra->append("\n",1); BEGIN(NOTCOMMENTS);
<SETUP>%%EndSetup.*\n BEGIN(NOTCOMMENTS);
<INITIAL,SETUP,ENDHEAD>.*\n
<*><<EOF>> yyterminate;
%%

223
modules/gmt/modgmt_map.cpp

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

34
modules/gmt/modgmt_map.h

@ -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

4
modules/gmt/modgmt_objects.cpp

@ -13,8 +13,8 @@ template<> const int8_t* ObjectGMTLayer::Blob(size_t* size) const
{
if(s.Shifted())
{
std::string b="V "+ToString(cm2GMT(s.shiftx))+" "+ToString(cm2GMT(s.shifty))+" T\n";
std::string e="U\n";
std::string b=s.BeginShift();
std::string e=s.EndShift();
int8_t* p=new int8_t[b.size()+s.data->size()+e.size()];
memcpy(p,b.data(),b.size());
memcpy(p+b.size(),s.data->data(),s.data->size());

9
modules/gmt/modgmt_objects.h

@ -8,15 +8,6 @@
#include "common.h"
#include "modgmt_structs.h"
// Centimeters to GMT points scale factor
// 1 inch = 72 pt = 2.54 cm --> 1 cm = 72/2.54 pt
// GMT's own scaling factor is 0.06
inline static double cm2GMT(double cm)
{
static const double scale=(72.0/2.54)/0.06;
return cm*scale;
}
template<class GMTStruct>
class ObjectGMTClass: public ObjectBase
{

11
modules/gmt/modgmt_structs.h

@ -6,6 +6,15 @@
#include "common.h"
#include "modgmt_colornames.h"
// Centimeters to GMT points scale factor
// 1 inch = 72 pt = 2.54 cm --> 1 cm = 72/2.54 pt
// GMT's own scaling factor is 0.06
inline static double cm2GMT(double cm)
{
static const double scale=(72.0/2.54)/0.06;
return cm*scale;
}
// Helper template for checking double numbers acquired from Source with some Policies.
// Main definition, never instantiated
template<class Source, class... Policies>
@ -807,5 +816,7 @@ struct gmt_layer: public gmt_struct
std::string Value() const {return creator+(Shifted()?("("+ToString(shiftx)+"x"+ToString(shifty)+")"):"");}
bool Shifted() const {return shiftx!=0.0 || shifty!=0.0;}
std::string BeginShift() const {return (Shifted()?("V "+ToString(cm2GMT(shiftx))+" "+ToString(cm2GMT(shifty))+" T\n"):"");}
std::string EndShift() const {return (Shifted()?"U\n":"");}
};
#endif

Loading…
Cancel
Save