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.
1056 lines
40 KiB
1056 lines
40 KiB
#ifndef MODGMT_FUNC_H |
|
#define MODGMT_FUNC_H |
|
#include "modgmt_internals.h" |
|
#include "modgmt_objects.h" |
|
#include "modgmt_param.h" |
|
|
|
const ObjectBase* GMT_Header(const ObjectList* input); |
|
const ObjectBase* GMT_Footer(const ObjectList* input); |
|
const ObjectBase* GMT_ColorGray(const ObjectList* input); |
|
const ObjectBase* GMT_ColorRGB(const ObjectList* input); |
|
const ObjectBase* GMT_ColorHSV(const ObjectList* input); |
|
const ObjectBase* GMT_ColorCMYK(const ObjectList* input); |
|
const ObjectBase* GMT_LayerShift(const ObjectList* input); |
|
|
|
// Generic converting template |
|
template<class Struct, class O> |
|
class Convert2Struct |
|
{ |
|
public: |
|
template<class... Args> |
|
Struct operator()(const O* o, bool* suc, std::string& err, Args... args) const |
|
{ |
|
Struct s; |
|
if(!s.Convert(o->Value(),err,args...)) *suc=false; |
|
return s; |
|
} |
|
}; |
|
// Extract structure from corresponding class |
|
template<class Struct> |
|
class Convert2Struct<Struct, ObjectGMTClass<Struct> > |
|
{ |
|
public: |
|
template<class... Args> |
|
Struct operator()(const ObjectGMTClass<Struct>* o, bool* suc, std::string& err, Args... args) const { return o->Data(); } // Never return error |
|
}; |
|
|
|
// Converting Int or Real to double |
|
template<class O> |
|
class Convert2Struct<double,O> |
|
{ |
|
public: |
|
double operator ()(const O* q, bool* suc, std::string& err) const {return q->Value();} |
|
}; |
|
// Converting String to double |
|
template<> |
|
class Convert2Struct<double,ObjectString> |
|
{ |
|
public: |
|
double operator ()(const ObjectString* q, bool* suc, std::string& err) const |
|
{ |
|
double d=0; |
|
bool res=str2double(q->Value(),&d); |
|
if(!res) err="Can't convert string "+q->Value()+" to double"; |
|
*suc=(*suc) && res; |
|
return d; |
|
} |
|
}; |
|
|
|
// Converting Int or Real to bool |
|
template<class O> |
|
class Convert2Struct<bool,O> |
|
{ |
|
public: |
|
bool operator ()(const O* q, bool* suc, std::string& err) const {return q->Value()!=0;} |
|
}; |
|
// Converting String to bool |
|
template<> |
|
class Convert2Struct<bool,ObjectString> |
|
{ |
|
public: |
|
bool operator ()(const ObjectString* q, bool* suc, std::string& err) const |
|
{ |
|
std::string v=q->Value(); |
|
tolower(v); |
|
if("y"==v || "yes"==v || "on"==v || "t"==v || "true"==v || "1"==v) return true; |
|
if("n"==v || "no"==v || "off"==v || "f"==v || "false"==v || "0"==v) return false; |
|
err="Can't convert string "+q->Value()+" to bool"; |
|
*suc=false; |
|
return false; |
|
} |
|
}; |
|
|
|
// Get string |
|
template<> |
|
class Convert2Struct<std::string,ObjectString> |
|
{ |
|
public: |
|
std::string operator ()(const ObjectString* q, bool* suc, std::string& err) const {return q->Value();} |
|
}; |
|
|
|
|
|
// Generic template for Converter class (using for read parameters) |
|
template<class Struct, class... Types> |
|
class BaseConverter |
|
{ |
|
template<class O> class StructConvertor: public Convert2Struct<Struct, O> {}; // Conversion type |
|
public: |
|
using ValueType=Struct; |
|
template<class... Args> |
|
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err, Args... args) |
|
{ |
|
OBTypeM<StructConvertor,Types...> gp(ob); |
|
switch(gp.Error()) |
|
{ |
|
case(OBTypeErr::OK): return gp(res,std::ref(err),args...); |
|
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;} |
|
case(OBTypeErr::TYPEMISMATCH): {err="Can't convert "+ob->Type()+": type mismatch"; break;} |
|
} |
|
*res=false; |
|
return ValueType(); |
|
} |
|
}; |
|
|
|
// Generic template for Converter class with default value (using for read parameters) |
|
template<class B> |
|
class DefaultConverter: public B |
|
{ |
|
public: |
|
using ValueType=typename B::ValueType; |
|
private: |
|
ValueType def; |
|
public: |
|
DefaultConverter() = delete; |
|
|
|
template<class... Args> |
|
DefaultConverter(const ValueType& d, Args... args):B(args...),def(d) {} |
|
template<class... Args> |
|
DefaultConverter(ValueType&& d, Args... args):B(args...),def(std::move(d)) {} |
|
|
|
const ValueType& Default() const {return def;} |
|
}; |
|
|
|
// Here we store type of Converter to type Struct. Generic template must never be used. |
|
template<class Struct> class TypeStorage; |
|
template<> class TypeStorage<double> {public: typedef BaseConverter<double, ObjectReal, ObjectInt, ObjectString > Converter;}; |
|
template<> class TypeStorage<bool> {public: typedef BaseConverter<bool, ObjectInt, ObjectReal, ObjectString > Converter;}; |
|
template<> class TypeStorage<std::string> {public: typedef BaseConverter<std::string, ObjectString > Converter;}; |
|
template<> class TypeStorage<struct gmt_coord> {public: typedef BaseConverter<struct gmt_coord, ObjectReal, ObjectInt, ObjectString,ObjectGMTCoord,ObjectList> Converter;}; |
|
template<> class TypeStorage<struct gmt_region> {public: typedef BaseConverter<struct gmt_region, ObjectList, ObjectString,ObjectGMTRegion > Converter;}; |
|
template<> class TypeStorage<struct gmt_projection> {public: typedef BaseConverter<struct gmt_projection,ObjectList, ObjectGMTProjection > Converter;}; |
|
template<> class TypeStorage<struct gmt_color> {public: typedef BaseConverter<struct gmt_color, ObjectList, ObjectString,ObjectReal,ObjectInt, ObjectGMTColor > Converter;}; |
|
template<> class TypeStorage<struct gmt_dash> {public: typedef BaseConverter<struct gmt_dash, ObjectString,ObjectGMTDash > Converter;}; |
|
template<> class TypeStorage<struct gmt_pen> {public: typedef BaseConverter<struct gmt_pen, ObjectList, ObjectString,ObjectReal,ObjectInt, ObjectGMTPen > Converter;}; |
|
template<> class TypeStorage<struct gmt_font> {public: typedef BaseConverter<struct gmt_font, ObjectList, ObjectString,ObjectReal,ObjectInt, ObjectGMTFont > Converter;}; |
|
template<> class TypeStorage<struct gmt_layer> {public: typedef BaseConverter<struct gmt_layer, ObjectList, ObjectGMTLayer > Converter;}; |
|
|
|
// Default ObjectList converter |
|
template<class Struct> |
|
class Convert2Struct<Struct, ObjectList> |
|
{ |
|
public: |
|
template<class... Args> |
|
Struct operator()(const ObjectList* o, bool* suc, std::string& err, Args... args) const |
|
{ |
|
Struct s; |
|
if(o->Size()!=1) {*suc=false; err="Can't convert list with more (or less) than one elements"; return s;} |
|
typename TypeStorage<Struct>::Converter a; |
|
s=a.Convert(o->At(0),suc,err,args...); |
|
return s; |
|
} |
|
}; |
|
|
|
// Template for simple aliases of convertors |
|
template<class Struct> |
|
using Base2Struct=typename TypeStorage<Struct>::Converter; |
|
// Template for simple aliases of convertors with default values |
|
template<class Struct> |
|
using Base2StructD=DefaultConverter<typename TypeStorage<Struct>::Converter>; |
|
|
|
// Simple aliases of convertors |
|
using Base2Double=Base2Struct<double>; |
|
using Base2String=Base2Struct<std::string>; |
|
using Base2Coord =Base2Struct<struct gmt_coord>; |
|
using Base2Region=Base2Struct<struct gmt_region>; |
|
using Base2Proj =Base2Struct<struct gmt_projection>; |
|
using Base2Color =Base2Struct<struct gmt_color>; |
|
using Base2Dash =Base2Struct<struct gmt_dash>; |
|
using Base2Pen =Base2Struct<struct gmt_pen>; |
|
using Base2Font =Base2Struct<struct gmt_font>; |
|
|
|
// Simple aliases of convertors with default values |
|
using Base2StringD=Base2StructD<std::string>; |
|
|
|
// Specialised convertors |
|
// Convertor with default value for gmt_coord. Added constructor for creating default value from double argument |
|
class Base2CoordD: public DefaultConverter<Base2Coord> |
|
{ |
|
static ValueType Def(double d) |
|
{ |
|
ValueType v; |
|
std::string fake; |
|
v.Convert(d,fake); |
|
return v; |
|
} |
|
public: |
|
using ValueType=DefaultConverter<Base2Coord>::ValueType; |
|
Base2CoordD(double d):DefaultConverter<Base2Coord>(Def(d)) {} |
|
}; |
|
|
|
// Convertor with default value for gmt_color. Added constructor for creating default value from double argument |
|
class Base2ColorD: public DefaultConverter<Base2Color> |
|
{ |
|
static ValueType Def(double d) |
|
{ |
|
ValueType v; |
|
std::string fake; |
|
v.Convert(d,fake); |
|
return v; |
|
} |
|
public: |
|
using ValueType=DefaultConverter<Base2Color>::ValueType; |
|
Base2ColorD(double d):DefaultConverter<Base2Color>(Def(d)) {} |
|
}; |
|
|
|
// Convertor with default value for gmt_dash. Default value is always no dash. |
|
class Base2DashD: public DefaultConverter<Base2Dash> |
|
{ |
|
static ValueType Def() |
|
{ |
|
ValueType v; |
|
v.Clear(); |
|
return v; |
|
} |
|
public: |
|
using ValueType=DefaultConverter<Base2Dash>::ValueType; |
|
Base2DashD():DefaultConverter<Base2Dash>(Def()) {} |
|
}; |
|
|
|
|
|
// Convertors for double positive value |
|
class Base2Pos: public Base2Double |
|
{ |
|
public: |
|
double Convert(const ObjectBase* ob, bool* res, std::string& err) |
|
{ |
|
double t=Base2Double::Convert(ob,res,err); |
|
if(res && t<=0) |
|
{ |
|
*res=false; |
|
err="Value mast be greater then zero"; |
|
} |
|
return t; |
|
} |
|
}; |
|
using Base2PosD=DefaultConverter<Base2Pos>; |
|
|
|
// Convertors for double non-negative value |
|
class Base2NonNeg: public Base2Double |
|
{ |
|
public: |
|
double Convert(const ObjectBase* ob, bool* res, std::string& err) |
|
{ |
|
double t=Base2Double::Convert(ob,res,err); |
|
if(res && t<0) |
|
{ |
|
*res=false; |
|
err="Value mast be non-negative"; |
|
} |
|
return t; |
|
} |
|
}; |
|
using Base2NonNegD=DefaultConverter<Base2NonNeg>; |
|
|
|
// Convertors for double values which must be in some interval |
|
template<int32_t Min, int32_t Max> |
|
class Base2InRange: public Base2Double |
|
{ |
|
public: |
|
double Convert(const ObjectBase* ob, bool* res, std::string& err) |
|
{ |
|
double t=Base2Double::Convert(ob,res,err); |
|
if(res && (t<Min || t>Max) ) |
|
{ |
|
*res=false; |
|
err="Value mast be in the interval from "+ToString(Min)+" to "+ToString(Max); |
|
} |
|
return t; |
|
} |
|
}; |
|
template<int32_t Min, int32_t Max> |
|
using Base2InRangeD=DefaultConverter<Base2InRange<Min,Max> >; |
|
|
|
// Definitions for colors |
|
constexpr int32_t TransMax = 100; |
|
constexpr int32_t RGBMax = 255; |
|
constexpr int32_t HueMax = 360; |
|
constexpr int32_t SVMax = 1; |
|
constexpr int32_t CMYKMax = 100; |
|
|
|
using Base2Trans = Base2InRange <0,TransMax>; |
|
using Base2RGB = Base2InRange <0,RGBMax >; |
|
using Base2Hue = Base2InRange <0,HueMax >; |
|
using Base2SV = Base2InRange <0,SVMax >; |
|
using Base2CMYK = Base2InRange <0,CMYKMax >; |
|
|
|
using Base2TransD = Base2InRangeD<0,TransMax>; |
|
using Base2RGBD = Base2InRangeD<0,RGBMax >; |
|
using Base2HueD = Base2InRangeD<0,HueMax >; |
|
using Base2SVD = Base2InRangeD<0,SVMax >; |
|
using Base2CMYKD = Base2InRangeD<0,CMYKMax >; |
|
|
|
// Conversion from List to GMTRegion |
|
/* |
|
Input: |
|
1) One argument, Region. Return copy of this argument. |
|
2) One argument, case insensitive string "global180" (global domain -R-180/180/-90/90), "global360" (global domain -R0/360/-90/90) or "global" (synonym of "global360"). |
|
3) One argument, list. Recursively calling GMT_Region. |
|
4) Pairs list. Names are xb, xe, yb, ye, and, optionally, type="bbox|nobbox|global180|global360|global". Names are case sensitive, values can be Int, Real, String or GMTCoord. |
|
If pair with name region (r) exists in list, when recursively calling GMT_Region on the value of this parameter, when modify it with specified parameters. |
|
If argument with type Region exists in list, when copy it and modify with specified parameters. |
|
5) 4 or 5 parameters. Fifth parameter can be "bbox" or "nobbox" (default). If fifth parameter is string "bbox", when first four parameters interprets as xb,yb,xe,ye, else as xb,xe,yb,ye. |
|
*/ |
|
template<> |
|
class Convert2Struct<struct gmt_region, ObjectList> |
|
{ |
|
public: |
|
struct gmt_region operator()(const ObjectList* input, bool* issuc, std::string& err) const |
|
{ |
|
struct gmt_region r; |
|
bool suc=true; |
|
|
|
if(1==input->Size()) // Cases 1, 2 and 3 |
|
{ |
|
Base2Region region; |
|
r=region.Convert(input->At(0),&suc,err); |
|
if(!suc) goto fail; // Conversion failed |
|
return r; |
|
} |
|
|
|
// Case 4 |
|
{ |
|
ONFPar<Base2Region,ObjectGMTRegion> region("region"); |
|
ONPar<Base2StringD> type("type","nobbox"); |
|
ONPar<Base2Coord> xb("xb"),xe("xe"),yb("yb"),ye("ye"); |
|
|
|
{ParseNamedParameters params(input,type,region,xb,xe,yb,ye); if(!params) {err=params.Error(); goto fail;} } // Fail to parse by variant 4 |
|
|
|
bool typeexist=type.Exist(); |
|
{ |
|
std::string t; |
|
if(r.Convert(type,t)) return r; // type is one of "global*" string, we can return, because upd is irrelevant |
|
} |
|
|
|
bool upd=region.Exist(); |
|
|
|
if(!(typeexist || xb.Exist() || xe.Exist() || yb.Exist() || ye.Exist() || upd)) goto case5; // No named parameters, no update mode, possibly case 5 |
|
struct gmt_coord cxb,cxe,cyb,cye; |
|
bool isbbox=upd?(gmt_region::BBOX==r.type):false; |
|
|
|
if(typeexist) |
|
{ |
|
if("bbox"==type.Value()) isbbox=true; |
|
if("nobbox"==type.Value()) isbbox=false; |
|
if("bbox"!=type.Value() && "nobbox"!=type.Value()) goto fail; // Unknown type |
|
} |
|
|
|
if(upd) |
|
{ |
|
cxb=xb.Exist()?xb:region->xb; |
|
cxe=xe.Exist()?xe:region->xe; |
|
cyb=yb.Exist()?yb:region->yb; |
|
cye=ye.Exist()?ye:region->ye; |
|
} |
|
else |
|
{ |
|
suc=suc && xb.Exist() && xe.Exist() && yb.Exist() && ye.Exist(); // In "new" mode all parameters must exists |
|
cxb=xb; cxe=xe; cyb=yb; cye=ye; |
|
} |
|
if(!suc) {err="To specify region all four coordinates must be set"; goto fail;} // Something wrong |
|
if(!r.Convert(cxb,cxe,cyb,cye,isbbox)) {err="Error conversion of coordinates to region"; goto fail;} // Conversion failed |
|
return r; // Case 3 with all parameters |
|
} |
|
|
|
case5: |
|
// Case 5 |
|
{ |
|
OPosPar<Base2StringD> type("type","nobbox"); |
|
RPosPar<Base2Coord> p1("p1"),p2("p2"),p3("p3"),p4("p4"); |
|
ParsePositionalParameters params(input,p1,p2,p3,p4,type); |
|
|
|
if(!params) {err=params.Error(); goto fail;} // Fail to parse by variant 5 |
|
|
|
bool isbbox=("bbox"==type.Value()); |
|
if("bbox"!=type.Value() && "nobbox"!=type.Value()) {err="Fifth parameter can be \"bbox\" or \"nobbox\" only"; goto fail;} // Unknown fifth parameter |
|
|
|
if(!r.Convert(p1,isbbox?p3:p2,isbbox?p2:p3,p4,isbbox)) {err="Error conversion of coordinates to region"; goto fail;} // Conversion failed |
|
return r; // Case 4 with all parameters |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return r; // Something go wrong |
|
} |
|
}; |
|
|
|
|
|
// Converting List to GMTProjection |
|
/* |
|
Input: |
|
1) One argument, Projection. Return copy of this argument. |
|
2) One argument, list. Recursively calling GMT_Projection. |
|
3) Pairs list. Names are projtype (type) (string), region (GMTRegion, string or list, which can be converted to GMTRegion), |
|
width (or height) in centimeters (may be absent, default width is 10 cm) and projection-dependent parameters. |
|
Pair with name region may absent, in this case search in list and using as region object with ObjectGMTRegion type. |
|
If pair with name projection (p or proj) exists in list, when recursively calling GMT_Projection on the value of this parameter, when modify it with specified parameters. |
|
If argument with type Projection exists in list, when copy it and modify with specified parameters. |
|
4) 3 or more parameters. First parameter is projection type (string), second - width in centimeters, |
|
third - region (any type which can be converted to GMTRegion), other parameters are projection-dependent. |
|
Height can be set only in form 3. |
|
*/ |
|
template<> |
|
class Convert2Struct<struct gmt_projection, ObjectList> |
|
{ |
|
public: |
|
struct gmt_projection operator()(const ObjectList* input, bool* issuc, std::string& err) const |
|
{ |
|
struct gmt_projection p; |
|
|
|
if(1==input->Size()) // Cases 1, and 2 |
|
{ |
|
Base2Proj proj; |
|
bool suc=true; |
|
p=proj.Convert(input->At(0),&suc,err); |
|
if(!suc) goto fail; // Conversion failed |
|
return p; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
bool upd; |
|
bool changetype=false; |
|
|
|
ONFPar<Base2Proj,ObjectGMTProjection> proj("projection"); |
|
ONFPar<Base2Region,ObjectGMTRegion> region("region"); |
|
ONPar<Base2StringD> type("[projection][( |_)]t[ype]","mercator"); |
|
ONPar<Base2PosD> width("width",gmt_projection::default_width),height("height",gmt_projection::default_width); |
|
|
|
{ParseNamedParameters params(input,type,region,proj,width,height); if(!params) {err=params.Error(); goto fail;}} // Fail to parse by variant 3 |
|
|
|
upd=proj.Exist(); |
|
if(upd) p=proj; |
|
|
|
if(!(type.Exist() || upd)) goto case4; // No named parameter, not update mode, go to case 4 |
|
|
|
// Check projection type |
|
if(type.Exist()) |
|
{ |
|
if(!p.SetType(type,err)) goto fail; // Incorrect projection type |
|
changetype=true; |
|
} |
|
|
|
// Region required in new mode |
|
if(!(region.Exist() || upd)) {err="Region must be specified"; goto fail;} |
|
if(region.Exist()) p.region=region; |
|
|
|
ONPar<Base2CoordD> cmer("c[entral][( |_)]meridian",(p.region.xb+p.region.xe)*0.5), stpar("s[tandar(t|d)][( |_)]parallel",(p.region.yb+p.region.ye)*0.5); |
|
ONPar<Base2CoordD> clon("(l[ongitude][( |_)][of( |_)]center|c[enter][( |_)]longitude)",(p.region.xb+p.region.xe)*0.5); |
|
ONPar<Base2CoordD> clat("(l[atitude][( |_)][of( |_)]center|c[enter][( |_)]latitude)",(p.region.yb+p.region.ye)*0.5); |
|
|
|
// Get parameters of projection |
|
switch(p.proj) |
|
{ |
|
case(gmt_projection::XY): // x Parameter height (by default equal width) |
|
{ |
|
// Width is processing later |
|
if(height.Exist()) p.x.height=height; |
|
else if(changetype) p.x.height=width; // By default, height equal width |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQU): // q Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
{ParseNamedParameters apar(input,cmer,stpar); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if( cmer.Exist() || changetype) p.q.cmer =cmer; |
|
if(stpar.Exist() || changetype) p.q.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::MERCATOR): // m Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
{ParseNamedParameters apar(input,cmer,stpar); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if( cmer.Exist() || changetype) p.m.cmer =cmer; |
|
if(stpar.Exist() || changetype) p.m.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::TRANSMERCATOR): // t Parameters: central meridian (cmer, default is center of region), latitude of origin (orlat, default is 0.0), scale factor (scale, default is 1.0) |
|
{ |
|
ONPar<Base2PosD> scale("scale",1.0); |
|
ONPar<Base2CoordD> orlat("(l[atitude][( |_)][of( |_)]origin|o[rigin][( |_)]latitude)",0.0); |
|
{ParseNamedParameters apar(input,cmer,scale,orlat); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if( cmer.Exist() || changetype) p.t.cmer =cmer; |
|
if(orlat.Exist() || changetype) p.t.orlat=orlat; |
|
if(scale.Exist() || changetype) p.t.scale=scale; |
|
break; |
|
} |
|
case(gmt_projection::OBLIQMERCATOR): // o Parameters: longitude of projection center (clon, default is center of region), latitude of projection center (clat, default is center of region). Other parameters may form one of three combinations and doesn't have default values. 1) Azimuth of the oblique equator (azimuth). 2) Longitude and latitude of second point on oblique equator (eqlon, eqlat). 3) Longitude and latitude of projection pole (polelon, polelat). |
|
{ |
|
ONPar<Base2Coord> eqlon("(l[ongitude][( |_)][of( |_)]equator|e[quator][( |_)]longitude)"), eqlat("(l[atitude][( |_)][of( |_)]equator|e[quator][( |_)]latitude)"); |
|
ONPar<Base2Coord> polelon("(l[ongitude][( |_)][of( |_)]pole|p[ole][( |_)]longitude)"), polelat("(l[atitude][( |_)][of( |_)]pole|p[ole][( |_)]latitude)"); |
|
ONPar<Base2Coord> azimuth("azimuth"); |
|
{ParseNamedParameters apar(input,clon,clat,eqlon,eqlat,polelon,polelat,azimuth); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
|
|
if(changetype) p.o.type=gmt_projection::OType::NOTDEF; |
|
|
|
if(clon.Exist() || changetype) p.o.clon=clon; |
|
if(clat.Exist() || changetype) p.o.clat=clat; |
|
// Check conflict in parameters |
|
if( |
|
(azimuth.Exist() && (eqlon.Exist() || eqlat.Exist() || polelon.Exist() || polelat.Exist() ) ) || |
|
( (eqlon.Exist() || eqlat.Exist()) && (azimuth.Exist() || polelon.Exist() || polelat.Exist() ) ) || |
|
( (polelon.Exist() || polelat.Exist()) && (azimuth.Exist() || eqlon.Exist() || eqlat.Exist() ) ) |
|
) |
|
{ |
|
err="Conflict in parameters for oblique Mercator projection, must specify only one variant: 1) azimuth of oblique equator, or 2) longitude and latitude of point on oblique equator, or 3) longitude and latitude of projection pole"; |
|
goto fail; // Insufficient data for this projection |
|
} |
|
// Variant 1 |
|
if(azimuth.Exist()) |
|
{ |
|
p.o.type=gmt_projection::OType::A; |
|
p.o.azimuth=azimuth; |
|
} |
|
// Variant 2 |
|
if(eqlon.Exist() && eqlat.Exist()) |
|
{ |
|
p.o.type=gmt_projection::OType::B; |
|
p.o.eqlon=eqlon; |
|
p.o.eqlat=eqlat; |
|
} |
|
// Variant 3 |
|
if(polelon.Exist() && polelat.Exist()) |
|
{ |
|
p.o.type=gmt_projection::OType::C; |
|
p.o.polelon=polelon; |
|
p.o.polelat=polelat; |
|
} |
|
// Special processing of update case |
|
if(!changetype) |
|
{ |
|
if(eqlon.Exist() && !eqlat.Exist()) |
|
{ |
|
if(gmt_projection::OType::B!=p.o.type) {err="Insufficient parameters for oblique Mercator projection, must specify latitude of point on oblique equator"; goto fail;} |
|
else p.o.eqlon=eqlon; |
|
} |
|
if(!eqlon.Exist() && eqlat.Exist()) |
|
{ |
|
if(gmt_projection::OType::B!=p.o.type) {err="Insufficient parameters for oblique Mercator projection, must specify longitude of point on oblique equator"; goto fail;} |
|
else p.o.eqlat=eqlat; |
|
} |
|
if(polelon.Exist() && !polelat.Exist()) |
|
{ |
|
if(gmt_projection::OType::C!=p.o.type) {err="Insufficient parameters for oblique Mercator projection, must specify latitude of projection pole"; goto fail;} |
|
else p.o.polelon=polelon; |
|
} |
|
if(!polelon.Exist() && polelat.Exist()) |
|
{ |
|
if(gmt_projection::OType::C!=p.o.type) {err="Insufficient parameters for oblique Mercator projection, must specify longitude of projection pole"; goto fail;} |
|
else p.o.polelat=polelat; |
|
} |
|
} |
|
if(gmt_projection::OType::NOTDEF==p.o.type) |
|
{ |
|
err="Insufficient parameters for oblique Mercator projection, must specify azimuth of oblique equator, or longitude and latitude of point on oblique equator, or longitude and latitude of projection pole"; |
|
goto fail; // Insufficient data for this projection |
|
} |
|
break; |
|
} |
|
case(gmt_projection::CASSINI): // c Parameters: longitude (clon, default is center of region) and latitude (clat, default is center of region) of central point. |
|
{ |
|
{ParseNamedParameters apar(input,clon,clat); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if(clon.Exist() || changetype) p.c.clon =clon; |
|
if(clat.Exist() || changetype) p.c.clat =clat; |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
{ParseNamedParameters apar(input,cmer,stpar); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if( cmer.Exist() || changetype) p.y.cmer =cmer; |
|
if(stpar.Exist() || changetype) p.y.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::MILLER): // j Parameters: central meridian (cmer, default is center of region) |
|
{ |
|
{ParseNamedParameters apar(input,cmer); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if(cmer.Exist() || changetype) p.j.cmer=cmer; |
|
break; |
|
} |
|
case(gmt_projection::CYL_STERE): // cyl_stere Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
{ParseNamedParameters apar(input,cmer,stpar); if(!apar) {err=apar.Error(); goto fail;}} // Fail to parse additional parameters |
|
if( cmer.Exist() || changetype) p.cyl_stere.cmer =cmer; |
|
if(stpar.Exist() || changetype) p.cyl_stere.stpar=stpar; |
|
break; |
|
} |
|
default: {err="Code error, unknown projection"; goto fail;} // Unknown projection |
|
} |
|
|
|
|
|
// Width and height manipulations |
|
if(width.Exist() && height.Exist() && gmt_projection::XY!=p.proj) {err="For geographic projections only one of width or height can be specified"; goto fail;} |
|
if(!upd) p.width=width; |
|
{ |
|
if(width.Exist()) // width is present |
|
{ |
|
p.width=width; |
|
if(!ProjectionRealSize(p)) goto failrealsize; // Something go wrong with determining real dimensions |
|
} |
|
else if(height.Exist()) // width is not present, but height is present |
|
{ |
|
if(gmt_projection::XY==p.proj) p.width=height; // For decart projection we use height as width if width is not specified |
|
if(!ProjectionRealSize(p,height)) goto failrealsize; |
|
} |
|
else // No width, no height, using default or old width |
|
if(!ProjectionRealSize(p)) goto failrealsize; // Something go wrong with determining real dimensions |
|
} |
|
return p; // All parameters setted |
|
failrealsize: |
|
err="Can't determine real size of projection "+p.Value(); |
|
goto fail; |
|
} |
|
|
|
case4: |
|
// Case 4 |
|
|
|
{ |
|
RPosPar<Base2String> type("projection type"); |
|
RPosPar<Base2Pos> width("width"); |
|
RPosPar<Base2Region> region("region"); |
|
|
|
{ParsePositionalParameters params(input,0,3,type,width,region); if(!params) {err=params.Error(); goto fail;}} // Fail to parse by variant 4 |
|
|
|
if(!p.SetType(type,err)) goto fail; // Incorrect projection type |
|
p.width=width; |
|
p.region=region; |
|
|
|
// Projection specific parameters |
|
switch(p.proj) |
|
{ |
|
case(gmt_projection::XY): // x Parameter 4 is height (by default equal width) |
|
{ |
|
OPosPar<Base2PosD> height("height",p.width); |
|
{ParsePositionalParameters params(input,3,input->Size(),height); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.x.height=height; |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQU): // q Parameters: 4 is central meridian (default is center of region), 5 is standart parallel (default is center of region) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> stpar("standart parallel",(p.region.yb+p.region.ye)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer,stpar); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.q.cmer=cmer; p.q.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::MERCATOR): // m Parameters: 4 is central meridian (default is center of region), 5 is standart parallel (default is center of region) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> stpar("standart parallel",(p.region.yb+p.region.ye)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer,stpar); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.m.cmer=cmer; p.m.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::TRANSMERCATOR): // t Parameters: 4 is central meridian (default is center of region), 5 is latitude of origin (default is 0.0), 6 is scale factor (default is 1.0) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> orlat("latitude of origin",0.0); |
|
OPosPar<Base2PosD> scale("scale",1.0); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer,orlat,scale); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.t.cmer=cmer; p.t.orlat=orlat; p.t.scale=scale; |
|
break; |
|
} |
|
case(gmt_projection::OBLIQMERCATOR): // o There is no default values for this projection. Parameters: 4 is subtype ("a" or "azimuth", "b" or "equator", "c" or "pole"), 5 is longitude of projection center, 6 is latitude of projection center. Other parameters may form one of three combinations. 1) 7 is azimuth of the oblique equator. 2) Longitude and latitude of second point on oblique equator (7, 8). 3) Longitude and latitude of projection pole (7, 8). |
|
{ |
|
RPosPar<Base2String> pstype("subtype"); |
|
RPosPar<Base2Coord> clon("longitude of center"); |
|
RPosPar<Base2Coord> clat("latitude of center"); |
|
|
|
{ParsePositionalParameters params(input,3,6,pstype,clon,clat); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
TemplateComparator a("azimuth"),b("(b|equator)"),c("(c|pole)"); |
|
std::string stype=pstype; |
|
tolower(stype); |
|
|
|
p.o.clon=clon; p.o.clat=clat; |
|
p.o.type=gmt_projection::OType::NOTDEF; |
|
|
|
// Variant 1 |
|
if(a.Compare(stype)) |
|
{ |
|
RPosPar<Base2Coord> azimuth("azimuth"); |
|
{ParsePositionalParameters params(input,6,input->Size(),azimuth); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.o.type=gmt_projection::OType::A; |
|
p.o.azimuth=azimuth; |
|
} |
|
if(b.Compare(stype)) |
|
{ |
|
RPosPar<Base2Coord> eqlon("longitude of equator"); |
|
RPosPar<Base2Coord> eqlat("latitude of equator"); |
|
{ParsePositionalParameters params(input,6,input->Size(),eqlon,eqlat); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.o.type=gmt_projection::OType::B; |
|
p.o.eqlon=eqlon; |
|
p.o.eqlat=eqlat; |
|
} |
|
if(c.Compare(stype)) |
|
{ |
|
RPosPar<Base2Coord> polelon("longitude of pole"); |
|
RPosPar<Base2Coord> polelat("latitude of pole"); |
|
{ParsePositionalParameters params(input,6,input->Size(),polelon,polelat); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.o.type=gmt_projection::OType::C; |
|
p.o.polelon=polelon; |
|
p.o.polelat=polelat; |
|
} |
|
if(gmt_projection::OType::NOTDEF==p.o.type) {err="String "+pstype.Value()+" is invalid subtype for oblique Mercator projection. The valid subtypes are azimuth, equator or pole"; goto fail;} |
|
break; |
|
} |
|
case(gmt_projection::CASSINI): // c Parameters: longitude (4, default is center of region) and latitude (5, default is center of region) of central point. |
|
{ |
|
OPosPar<Base2CoordD> clon("longitude of center",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> clat("latitude of center",(p.region.yb+p.region.ye)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),clon,clat); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.c.clon=clon; p.c.clat=clat; |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (4, default is center of region), standart parallel (5, default is center of region) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> stpar("standart parallel",(p.region.yb+p.region.ye)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer,stpar); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.y.cmer=cmer; p.y.stpar=stpar; |
|
break; |
|
} |
|
case(gmt_projection::MILLER): // j Parameters: central meridian (4, default is center of region) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.j.cmer=cmer; |
|
break; |
|
} |
|
case(gmt_projection::CYL_STERE): // cyl_stere Parameters: central meridian (3, default is center of region), standart parallel (4, default is center of region) |
|
{ |
|
OPosPar<Base2CoordD> cmer("central meridian",(p.region.xb+p.region.xe)*0.5); |
|
OPosPar<Base2CoordD> stpar("standart parallel",(p.region.yb+p.region.ye)*0.5); |
|
{ParsePositionalParameters params(input,3,input->Size(),cmer,stpar); if(!params) {err=params.Error(); goto fail;}} // Fail to parse additional parameters |
|
p.cyl_stere.cmer=cmer; p.cyl_stere.stpar=stpar; |
|
break; |
|
} |
|
default: goto fail; // Unknown projection |
|
} |
|
if(ProjectionRealSize(p)) return p; |
|
err="Can't determine real size of projection "+p.Value(); |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return p; // Something go wrong |
|
} |
|
}; |
|
|
|
// Converting List to GMTColor |
|
/* |
|
Input: |
|
1) One argument, Color. Return copy of this argument. |
|
2) One argument, list. Recursively calling GMT_Color. |
|
3) Pairs list. Names are gray (grey), r(red),g(green),b(blue), h(hue),s(sat,saturation),v(value), c(cyan),m(magenta),y(yellow),k(black) and t(transp,transparency). |
|
The different color models can't be mixed. |
|
Gray, r, g, b are doubles in the range 0-255, h is double in the range 0-360, s and v are doubles in the range 0-1 and c, m, y, k and transparency are doubles in the range 0-100. Default value for all parameters is 0. |
|
If pair with name color exists in list, when recursively calling GMT_Color on the value of this parameter, when modify it with specified parameters. |
|
If argument with type Color exists in list, when copy it and modify with specified parameters. In both cases color model changing as specified by parameters. |
|
4) One argument, interprets as gray. |
|
5) Three arguments, interprets as r, g, b. |
|
6) Four arguments, interprets as c, m, y, k. |
|
Transparency or HSV model can be set only in form 3. |
|
*/ |
|
template<> |
|
class Convert2Struct<struct gmt_color, ObjectList> |
|
{ |
|
public: |
|
struct gmt_color operator()(const ObjectList* input, bool* issuc, std::string& err) const |
|
{ |
|
struct gmt_color C; |
|
|
|
if(1==input->Size()) // Cases 1, 2 and 4 |
|
{ |
|
Base2Color color; |
|
bool suc=true; |
|
C=color.Convert(input->At(0),&suc,err); |
|
if(!suc) goto fail; // Conversion failed |
|
return C; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
ONFPar<Base2Color,ObjectGMTColor> color("color"); |
|
ONPar<Base2TransD> trans("transparency",0); |
|
ONPar<Base2RGB> gray("gr(a|e)y"), r("red"), g("green"), b("blue"); |
|
ONPar<Base2Hue> h("hue"); |
|
ONPar<Base2SV> s("saturation"), v("value"); |
|
ONPar<Base2CMYK> c("cyan"), m("magenta"), y("yellow"), k("[blac]k"); |
|
|
|
{ParseNamedParameters params(input,color,trans,gray,r,g,b,h,s,v,c,m,y,k); if(!params) {err=params.Error(); goto fail;} } // Fail to parse by variant 3 |
|
|
|
bool cmodset=false; |
|
bool upd=color.Exist(); |
|
|
|
if(!upd) |
|
{ |
|
// default color is black |
|
C.transparency=trans; |
|
C.model=gmt_color::GRAY; |
|
C.gray=0.0; |
|
} |
|
else C=color; |
|
|
|
if(trans.Exist()) C.transparency=trans; |
|
|
|
// GRAY |
|
if(gray.Exist()) |
|
{ |
|
if(cmodset) {err="Can't select between different color models"; goto fail;} // Model already set |
|
C.model=gmt_color::GRAY; |
|
C.gray=gray; // Update mode ignored in this case |
|
cmodset=true; |
|
} |
|
|
|
// RGB |
|
if(r.Exist() || g.Exist() || b.Exist()) |
|
{ |
|
if(cmodset) {err="Can't select between different color models"; goto fail;} // Model already set |
|
C.ToRGB(); |
|
if(r.Exist()) C.r=r; |
|
if(g.Exist()) C.g=g; |
|
if(b.Exist()) C.b=b; |
|
cmodset=true; |
|
} |
|
|
|
// HSV |
|
if(h.Exist() || s.Exist() || v.Exist()) |
|
{ |
|
if(cmodset) {err="Can't select between different color models"; goto fail;} // Model already set |
|
C.ToHSV(); |
|
if(h.Exist()) C.hue=h; |
|
if(s.Exist()) C.saturation=s; |
|
if(v.Exist()) C.value=v; |
|
cmodset=true; |
|
} |
|
|
|
// CMYK |
|
if(c.Exist() || m.Exist() || y.Exist() || k.Exist()) |
|
{ |
|
if(cmodset) {err="Can't select between different color models"; goto fail;} // Model already set |
|
C.ToCMYK(); |
|
if(c.Exist()) C.cyan=c; |
|
if(m.Exist()) C.magenta=m; |
|
if(y.Exist()) C.yellow=y; |
|
if(k.Exist()) C.black=k; |
|
cmodset=true; |
|
} |
|
|
|
if(cmodset || upd) return C; // Color created or updated |
|
} |
|
|
|
// Case 5 |
|
if(3==input->Size()) |
|
{ |
|
RPosPar<Base2RGB> r("red"), g("green"), b("blue"); |
|
ParsePositionalParameters params(input,r,g,b); |
|
|
|
if(!params) {err=params.Error(); goto fail;} // Fail to parse by variant 5 |
|
|
|
C.model=gmt_color::RGB; |
|
C.r=r; C.g=g; C.b=b; |
|
return C; |
|
} |
|
|
|
// Case 6 |
|
if(4==input->Size()) |
|
{ |
|
RPosPar<Base2CMYK> c("cyan"), m("magenta"), y("yellow"), k("black"); |
|
ParsePositionalParameters params(input,c,m,y,k); |
|
|
|
if(!params) {err=params.Error(); goto fail;} // Fail to parse by variant 6 |
|
C.model=gmt_color::CMYK; |
|
C.cyan=c; C.magenta=m; C.yellow=y; C.black=k; |
|
return C; |
|
} |
|
err="Incorrect number of arguments"; |
|
|
|
fail: |
|
*issuc=false; |
|
return C; // Something go wrong |
|
} |
|
}; |
|
|
|
|
|
// Converting List to GMTPen |
|
/* |
|
Input: |
|
1) One argument, Pen. Return copy of this argument. |
|
2) One argument, list. Recursively calling GMT_Pen. |
|
3) Pairs list. Names are width (w), color(c), dash(f). Default values is 1 for width, black for color and solid for dash. |
|
If pair with name pen(p) exists in list, when recursively calling GMT_Line on the value of this parameter, when modify it with specified parameters. |
|
If argument with type Pen exists in list, when copy it and modify with specified parameters. |
|
Instead of color and dash unnamed parameters with Color and Dash types may be used. |
|
4) One argument, interprets as width of black solid line. |
|
5) Two arguments, interprets as width and color of solid line. |
|
6) Three arguments, interprets as width, color and dash. |
|
*/ |
|
|
|
template<> |
|
class Convert2Struct<struct gmt_pen, ObjectList> |
|
{ |
|
public: |
|
|
|
struct gmt_pen operator()(const ObjectList* input, bool* issuc, std::string& err) const |
|
{ |
|
struct gmt_pen p; |
|
|
|
if(1==input->Size()) // Cases 1, 2 and 4 |
|
{ |
|
Base2Pen pen; |
|
bool suc=true; |
|
p=pen.Convert(input->At(0),&suc,err); |
|
if(!suc) goto fail; // Conversion failed |
|
return p; |
|
} |
|
|
|
// Case 5 and 6 |
|
{ |
|
OPosPar<Base2NonNegD> width("width",gmt_pen::default_width); |
|
OPosPar<Base2ColorD> color("color",0.0); |
|
OPosPar<Base2DashD> dash("dash"); |
|
|
|
ParsePositionalParameters params(input,width,color,dash); |
|
if(!params) goto case3; // May be case3 will work |
|
p.color=color; |
|
p.dash=dash; |
|
p.dash.width=p.width=width; |
|
return p; |
|
} |
|
|
|
// Case 3 |
|
case3: |
|
{ |
|
bool upd; |
|
ONFPar<Base2Pen,ObjectGMTPen> pen("pen"); |
|
ONFPar<Base2ColorD,ObjectGMTColor> color("color",0.0); |
|
ONFPar<Base2DashD,ObjectGMTDash> dash("dash"); |
|
ONPar<Base2NonNegD> width("width",gmt_pen::default_width); |
|
|
|
{ParseNamedParameters params(input,color,pen,dash,width); if(!params) {err=params.Error(); goto fail;} } // Fail to parse by variant 3 |
|
|
|
upd=pen.Exist(); |
|
if(upd) p=pen; |
|
if(color.Exist() || !upd) p.color=color; |
|
if(dash.Exist() || !upd) p.dash=dash; |
|
if(width.Exist() || !upd) p.width=width; |
|
p.dash.width=p.width; |
|
|
|
if(color.Exist() || dash.Exist() || width.Exist() || upd) return p; // Pen created or updated |
|
err="Specify at least one of color, dash or width"; |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return p; // Something go wrong |
|
} |
|
}; |
|
|
|
|
|
// Converting List to GMTFont |
|
/* |
|
Input: |
|
1) One argument, Font. Return copy of this argument. |
|
2) One argument, list. Recursively calling GMT_Font. |
|
3) Pairs list. Names are size (s), family (f) and color(c). Default values is 12pt for size, Times-Roman for family and black for color. |
|
If pair with name font exists in list, when recursively calling GMT_Font on the value of this parameter, when modify it with specified parameters. |
|
If argument with type Font exists in list, when copy it and modify with specified parameters. |
|
Instead of color unnamed parameter with Color type may be used. |
|
4) One numeric argument, interprets as size of Times-Roman black font. |
|
5) One string argument, interprets as [size][,family][,color] or [family][,color]. |
|
6) Two arguments, interprets as size and family of black font. |
|
7) Three arguments, interprets as size, family and color. |
|
*/ |
|
|
|
template<> |
|
class Convert2Struct<struct gmt_font, ObjectList> |
|
{ |
|
public: |
|
|
|
struct gmt_font operator()(const ObjectList* input, bool* issuc, std::string& err) const |
|
{ |
|
struct gmt_font f; |
|
|
|
if(1==input->Size()) // Cases 1, 2, 4 and 5 |
|
{ |
|
Base2Font font; |
|
bool suc=true; |
|
f=font.Convert(input->At(0),&suc,err); |
|
if(!suc) goto fail; // Conversion failed |
|
return f; |
|
} |
|
|
|
// Case 6 and 7 |
|
{ |
|
OPosPar<Base2PosD> size("size",gmt_font::default_size); |
|
OPosPar<Base2ColorD> color("color",0.0); |
|
OPosPar<Base2StringD> family("family",gmt_font::default_family); |
|
|
|
ParsePositionalParameters params(input,size,family,color); |
|
if(!params) goto case3; // May be case3 will work |
|
f.color=color; |
|
f.size=size; |
|
f.family=family; |
|
return f; |
|
} |
|
|
|
// Case 3 |
|
case3: |
|
{ |
|
ONFPar<Base2Font,ObjectGMTFont> font("f[on]t"); |
|
ONFPar<Base2ColorD,ObjectGMTColor> color("color",0); |
|
ONFPar<Base2StringD,ObjectString> family("f[a]m[i]ly",gmt_font::default_family); |
|
ONFPar<Base2PosD,ObjectReal> size("size",gmt_font::default_size); |
|
|
|
{ParseNamedParameters params(input,font,color,family,size); if(!params) {err=params.Error(); goto fail;} } // Fail to parse by variant 3 |
|
|
|
bool upd=font.Exist(); |
|
if(upd) f=font; |
|
if(color.Exist() || !upd) f.color =color; |
|
if(family.Exist() || !upd) f.family=family; |
|
if(size.Exist() || !upd) f.size =size; |
|
|
|
|
|
if(color.Exist() || family.Exist() || size.Exist() || upd) return f; // Font created or updated |
|
err="Specify at least one of size, family or color"; |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return f; // Something go wrong |
|
} |
|
}; |
|
|
|
// Template for generating GMTObject from ObjectList |
|
template<class Struct> |
|
const ObjectBase* GMT_Type(const ObjectList* input) |
|
{ |
|
bool suc=true; |
|
Struct s=Convert2Struct<Struct,ObjectList>()(input,&suc); |
|
if(suc) return new ObjectGMTClass<Struct>(s); |
|
else return 0; |
|
} |
|
|
|
// Shift position of layer |
|
const ObjectBase* GMT_LayerShift(const ObjectList* input); |
|
|
|
// Draw frame with tics |
|
const ObjectBase* GMT_DrawFrame(const ObjectList* input); |
|
|
|
#endif
|
|
|