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.
313 lines
11 KiB
313 lines
11 KiB
#include "modgmt_func.h" |
|
|
|
static double AutoStep(double b, double e) |
|
{ |
|
double n=pow(10.0,ceil(log10(e-b)-1.0)); |
|
double steps[]={0.5,1,2,5,10,0}; |
|
double div=0.0; |
|
uint i=0; |
|
|
|
do if((e-b)*steps[i]/n<10.0) div=n/steps[i]; while(0.0!=steps[++i]); |
|
return div; |
|
} |
|
|
|
const ObjectBase* GMT_Header(const ObjectList* input) |
|
{ |
|
return new ObjectString(header); |
|
} |
|
|
|
const ObjectBase* GMT_Footer(const ObjectList* input) |
|
{ |
|
return new ObjectString(footer); |
|
} |
|
|
|
const ObjectBase* GMT_Datadir(const ObjectList* input) |
|
{ |
|
return new ObjectString(datadir); |
|
} |
|
|
|
const ObjectBase* GMT_ColorGray(const ObjectList* input) |
|
{ |
|
struct gmt_color c; |
|
RPosPar<Base2RGB> g("gray"); |
|
OPosPar<Base2TransD> t("transparency",0.0); |
|
|
|
ParsePositionalParameters params(input,g,t); |
|
if(!params) return new ObjectError("ColorGray",params.Error()); |
|
|
|
c.model=gmt_color::GRAY; |
|
c.gray=g; c.transparency=t; |
|
|
|
return new ObjectGMTColor(c); |
|
} |
|
|
|
const ObjectBase* GMT_ColorRGB(const ObjectList* input) |
|
{ |
|
struct gmt_color c; |
|
|
|
RPosPar<Base2RGB> r("red"),g("green"),b("blue"); |
|
OPosPar<Base2TransD> t("transparency",0.0); |
|
|
|
ParsePositionalParameters params(input,r,g,b,t); |
|
if(!params) return new ObjectError("ColorRGB",params.Error()); |
|
|
|
c.model=gmt_color::RGB; |
|
c.r=r; c.g=g; c.b=b; c.transparency=t; |
|
|
|
return new ObjectGMTColor(c); |
|
} |
|
|
|
const ObjectBase* GMT_ColorHSV(const ObjectList* input) |
|
{ |
|
struct gmt_color c; |
|
|
|
RPosPar<Base2Hue> h("hue"); |
|
RPosPar<Base2SV> s("saturation"), v("value"); |
|
OPosPar<Base2TransD> t("transparency",0.0); |
|
|
|
ParsePositionalParameters params(input,h,s,v,t); |
|
if(!params) return new ObjectError("ColorHSV",params.Error()); |
|
|
|
c.model=gmt_color::HSV; |
|
c.hue=h; c.saturation=s; c.value=v; c.transparency=t; |
|
|
|
return new ObjectGMTColor(c); |
|
} |
|
|
|
const ObjectBase* GMT_ColorCMYK(const ObjectList* input) |
|
{ |
|
struct gmt_color C; |
|
|
|
RPosPar<Base2CMYK> c("cyan"),m("magenta"),y("yellow"),k("black"); |
|
OPosPar<Base2TransD> t("transparency",0.0); |
|
|
|
ParsePositionalParameters params(input,c,m,y,k,t); |
|
if(!params) return new ObjectError("ColorCMYK",params.Error()); |
|
|
|
C.model=gmt_color::CMYK; |
|
C.cyan=c; C.magenta=m; C.yellow=y; C.black=k; C.transparency=t; |
|
|
|
return new ObjectGMTColor(C); |
|
} |
|
|
|
// Shifting layer |
|
/* |
|
Input: |
|
1) Three arguments, first is Layer, second and third are double. Interprets as new absolute position in cm. |
|
2) Pairs list. Names are l (layer), x, y, relx (rx), rely (ry). Pair with name l may be absent, in this case search in list and using as layer object with ObjectGMTLayer type. x and y are absolute positions in cm, relx and rely are shift from current position. x (y) and relx (rely) are mutually exlusive, but x (y) and rely (relx) can be used simultaneously. If position for some axis is absent, then this position is unchanged. |
|
*/ |
|
const ObjectBase* GMT_LayerShift(const ObjectList* input) |
|
{ |
|
struct gmt_layer layer; |
|
std::string err; |
|
|
|
// Case 1 |
|
{ |
|
RPosPar<Base2Layer> l("layer"); |
|
OPosPar<Base2DoubleD> x("x",0.0), y("y",0.0); |
|
|
|
{ParsePositionalParameters params(input,l,x,y); if(!params) goto case2;} // Try case 2, if case 1 failed. |
|
layer=l; layer.shiftx=x; layer.shifty=y; |
|
return new ObjectGMTLayer(layer); |
|
} |
|
|
|
case2: |
|
{ |
|
RNPar<Base2Layer> l("layer"); |
|
ONPar<Base2Double> x("x"),y("y"),rx("r[el]x"),ry("r[el]y"); |
|
|
|
{ParseNamedParameters params(input,l,x,y); if(!params) {err=params.Error(); goto fail;}} // Parsing error |
|
|
|
// Check duplicate parameters |
|
if(x.Exist() && rx.Exist()) {err="Only one of "+x.Name()+" or "+rx.Name()+" can be specified."; goto fail;} |
|
if(y.Exist() && ry.Exist()) {err="Only one of "+y.Name()+" or "+ry.Name()+" can be specified."; goto fail;} |
|
// Do shift |
|
if( x.Exist()) layer.shiftx=x; |
|
if( y.Exist()) layer.shifty=y; |
|
if(rx.Exist()) layer.shiftx+=rx; |
|
if(ry.Exist()) layer.shifty+=ry; |
|
} |
|
|
|
return new ObjectGMTLayer(layer); |
|
|
|
fail: |
|
return new ObjectError("LayerShift",err); |
|
} |
|
|
|
// Draw frame with tics |
|
/* |
|
Input: pairs list. |
|
proj or projection or unnamed GMTProjection parameter - projection. This is mandatory argument. |
|
xtics - position of tics for x axis. Can be none, up, down or both. Default is down. |
|
ytics - position of tics for y axis. Can be none, left, right or both. Default is left. |
|
xint - tics interval for x axis. Numerical value or word auto. Default is auto. |
|
yint - tics interval for y axis. Numerical value or word auto. Default is auto. |
|
domain - coordinates domain. Can be pos (0:360), neg (-360:0) or center (-180:180) (only for geographic projections). Default is pos. |
|
mark - using letters (W, E, S, N) instead of sign for coordinates (only for geographic projections). Can be yes or no. Default is no. |
|
font - font using for annotations. Default is 12,Times-Roman,black. |
|
offset - distance from end of tick-mark to start of annotation in cm. Default is 0.18. |
|
framewidth - width of frame (only for geographic projections) in cm. Default is 0.1. |
|
framepen - pen for drawing frame. Default is 0.35,black. |
|
ticklen - lenght of tick-marks in cm. Default is 0.18. |
|
tickpen - pen for drawing ticks. Default is 0.3,black. |
|
trans or transparency - transparency level, double from 0 to 100. Default is 0 (opaque). |
|
model - transparency model, string. Choose from Color, ColorBurn, ColorDodge, Darken, Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, Overlay, Saturation, SoftLight, and Screen. Default is Normal. |
|
rx or relx - shift layer on x cm in horisontal direction. Default is 0. |
|
ry or rely - shift layer on y cm in vertical direction. Default is 0. |
|
*/ |
|
template<class O> |
|
using SConvertor=Convert2Struct<std::string, O>; |
|
template<class O> |
|
using DConvertor=Convert2Struct<double, O>; |
|
|
|
const ObjectBase* GMT_DrawFrame(const ObjectList* input) |
|
{ |
|
struct XYIntVal // Representing intervals for tics intervals |
|
{ |
|
bool isauto; double val; |
|
XYIntVal():isauto(true),val(0.0) {} // Default is auto |
|
}; |
|
|
|
class Base2TInt // Custom convertor class for xy tics intervals |
|
{ |
|
public: |
|
using ValueType=struct XYIntVal; |
|
|
|
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err) |
|
{ |
|
ValueType ret; |
|
ret.isauto=false; |
|
|
|
OBTypeM<SConvertor,ObjectString> sp(ob); |
|
OBTypeM<DConvertor,ObjectReal,ObjectInt,ObjectString> dp(ob); |
|
// Check string "auto" |
|
if(sp.Error()==OBTypeErr::OK) |
|
{ |
|
std::string s=sp(res,std::ref(err)); |
|
if(!res) {err="Unknown error"; goto fail;} // Impossible case |
|
tolower(s); |
|
if("auto"==s) {ret.isauto=true; return ret;} |
|
} |
|
// Check double value |
|
switch(dp.Error()) |
|
{ |
|
case(OBTypeErr::OK): |
|
{ |
|
ret.val=dp(res,std::ref(err)); |
|
if(ret.val<=0.0) {err="Tics interval must be greater the zero"; break;} |
|
return ret; |
|
}; |
|
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;} |
|
case(OBTypeErr::TYPEMISMATCH): {err="Can't convert "+ob->Type()+" to double: type mismatch"; break;} |
|
} |
|
fail: |
|
*res=false; |
|
return ret; |
|
} |
|
}; |
|
|
|
std::string err,fakerr; |
|
std::string opts="-P -O -K "; |
|
|
|
struct gmt_layer layer; |
|
|
|
struct gmt_font deffont; |
|
struct gmt_pen defframepen,deftickpen; |
|
deffont.Convert("12,Times-Roman,black",fakerr); |
|
defframepen.Convert("0.35,black",fakerr); |
|
deftickpen.Convert("0.3,black",fakerr); |
|
|
|
RNFPar<Base2Proj,ObjectGMTProjection> proj("projection"); |
|
ONPar<Base2TInt> xint("x[ ]interval"), yint("y[ ]interval"); |
|
ONPar<Base2StringD> xtics("x[ ]tics[ ]position","down"), ytics("y[ ]t[ics[ ]position","left"); |
|
ONPar<Base2StringD> domain("domain","pos"); |
|
ONPar<Base2BoolD> mark("mark",false); |
|
ONPar<Base2FontD> font("font",deffont); |
|
ONPar<Base2DoubleD> offset("offset",0.18); |
|
ONPar<Base2NonNegD> framewidth("f[rame][ ]width",0.1); |
|
ONPar<Base2PenD> framepen("f[rame][ ]pen",defframepen), tickpen("t[icks][ ]pen",deftickpen); |
|
ONPar<Base2DoubleD> ticklen("t[icks][ ]length",0.18); |
|
ONPar<Base2TransD> transp("transparency",0.0); |
|
ONPar<Base2StringD> transpmodel("model","Normal"); |
|
ONPar<Base2DoubleD> rx("r[el]x",0.0),ry("r[el]y",0.0); |
|
|
|
ParseNamedParameters params(input,proj,xint,yint,xtics,ytics,domain,mark,font,offset,framewidth,framepen,tickpen,ticklen,transp,transpmodel,rx,ry); if(!params) {err=params.Error(); goto fail;} // Error parsing parameters |
|
|
|
layer.proj=proj; // Get projection |
|
opts+=layer.proj.Value()+" "; |
|
|
|
{ // Get tics intervals |
|
XYIntVal dx=xint,dy=yint; |
|
opts+="-Bx"+ToString(dx.isauto?AutoStep(layer.proj.region.xb,layer.proj.region.xe):dx.val)+" -By"+ToString(dy.isauto?AutoStep(layer.proj.region.yb,layer.proj.region.ye):dy.val)+" "; |
|
} |
|
|
|
{ // Get xtics and ytics positions |
|
std::string xt=xtics, yt=ytics; |
|
std::string xaxis, yaxis; |
|
TemplateComparator none("none"), both("both"); |
|
TemplateComparator up("up"), down("down"); |
|
TemplateComparator left("left"), right("right"); |
|
tolower(xt); tolower(yt); |
|
|
|
if(none.Compare(xt)) xaxis="sn"; |
|
if(down.Compare(xt)) xaxis="Sn"; |
|
if( up.Compare(xt)) xaxis="sN"; |
|
if(both.Compare(xt)) xaxis="SN"; |
|
|
|
if( none.Compare(yt)) yaxis="we"; |
|
if( left.Compare(yt)) yaxis="We"; |
|
if(right.Compare(yt)) yaxis="wE"; |
|
if( both.Compare(yt)) yaxis="WE"; |
|
|
|
if(xaxis.empty()) {err="Incorrect xtics position "+xtics.Value(); goto fail;} // Unknown value of xtics |
|
if(yaxis.empty()) {err="Incorrect xtics position "+ytics.Value(); goto fail;} // Unknown value of ytics |
|
opts+="-B"+xaxis+yaxis+" "; |
|
} |
|
|
|
{ // Get domain and mark |
|
std::string dom=domain; |
|
std::string format; |
|
TemplateComparator p("positive"),n("negative"),c("centered"); |
|
tolower(dom); |
|
|
|
if(p.Compare(dom)) format="+ddd:mm:ss"; |
|
if(n.Compare(dom)) format="-ddd:mm:ss"; |
|
if(c.Compare(dom)) format="ddd:mm:ss"; |
|
if(format.empty()) {err="Incorrect domain value "+domain.Value(); goto fail;} // Unknown domain |
|
|
|
if(mark) format+="F"; |
|
opts+="--FORMAT_GEO_MAP="+format+" "; |
|
} |
|
|
|
opts+="--FONT_ANNOT_PRIMARY="+font.Value().Value()+" "; // Get font |
|
opts+="--MAP_ANNOT_OFFSET_PRIMARY="+ToString(offset.Value())+"c "; // Get offset |
|
opts+="--MAP_FRAME_WIDTH="+ToString(framewidth.Value())+"c "; // Get framewidth |
|
opts+="--MAP_FRAME_PEN="+framepen.Value().Value()+" "; // Get framepen |
|
opts+="--MAP_TICK_LENGTH_PRIMARY="+ToString(ticklen.Value())+"c "; // Get ticklen |
|
opts+="--MAP_TICK_PEN_PRIMARY="+tickpen.Value().Value()+" "; // Get tickpen |
|
if(transp!=0) opts+="-t"+ToString(transp.Value())+" "; // Get transparency |
|
opts+="--PS_TRANSPARENCY="+transpmodel.Value()+" "; // Get transparency model |
|
|
|
// Get shift |
|
layer.shiftx=rx; |
|
layer.shifty=ry; |
|
|
|
{ // Calling psbasemap |
|
void* gmtapi; |
|
std::string* draw=new std::string; |
|
int ret; |
|
|
|
gmtapi=GMT_Create_Session("DrawFrame",2,GMTMODE,0); |
|
if(0==gmtapi) goto fail; // Can't create GMT GMT_Create_Session |
|
ret=callgmtmodule(gmtapi,"psbasemap",opts,draw); |
|
GMT_Destroy_Session(gmtapi); |
|
if(0!=ret) {delete draw; goto fail;} // Psbasemap error |
|
layer.data.reset(draw); |
|
} |
|
|
|
layer.creator="psbasemap "+opts; |
|
return new ObjectGMTLayer(layer); |
|
|
|
fail: |
|
return new ObjectError("DrawFrame",err); |
|
}
|
|
|