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.
1447 lines
47 KiB
1447 lines
47 KiB
#ifndef MODGMT_FUNC_H |
|
#define MODGMT_FUNC_H |
|
#include "modgmt_internals.h" |
|
#include "modgmt_objects.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); |
|
|
|
// Extension of OBTypeM template for easy work with lists |
|
template<template<typename> class Func, class... O> |
|
class Base2Something: public OBTypeM<Func,O...> |
|
{ |
|
Base2Something() = delete; |
|
Base2Something(Base2Something&&) = delete; |
|
Base2Something(Base2Something&) = delete; |
|
|
|
public: |
|
Base2Something(const ObjectBase* arg):OBTypeM<Func,O...>(arg) {}; |
|
Base2Something(const ObjectList* input, const std::string& name):OBTypeM<Func,O...>(input->Find(name)){}; |
|
Base2Something(const ObjectList* input, const ObjectList::IndexType i):OBTypeM<Func,O...>((i<input->Size())?input->At(i):0){}; // Check index, because At is not safe |
|
template<class... Args> |
|
auto operator ()(bool* b, Args... args) const -> decltype(this->OBTypeM<Func,O...>::template operator()<bool*, Args...>(b, args...)) |
|
{ |
|
if(!OBTypeM<Func,O...>::operator bool()) *b=false; |
|
return OBTypeM<Func,O...>::operator ()(b,args...); |
|
} |
|
}; |
|
|
|
// Generic converting template |
|
template<class Struct, class O> |
|
class Convert2Struct |
|
{ |
|
public: |
|
template<class... Args> |
|
Struct operator()(const O* o, bool* suc, Args... args) const |
|
{ |
|
Struct s; |
|
if(!s.Convert(o->Value(),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, Args... args) const { return o->Data(); } |
|
}; |
|
|
|
// Converting Int or Real to double |
|
template<class O> |
|
class Convert2Struct<double,O> |
|
{ |
|
public: |
|
double operator ()(const O* q, bool* suc) const {return q->Value();} |
|
}; |
|
// Converting String to double |
|
template<> |
|
class Convert2Struct<double,ObjectString> |
|
{ |
|
public: |
|
double operator ()(const ObjectString* q, bool* suc) const {double d=0; *suc=(*suc) && str2double(q->Value(),&d); return d;} |
|
}; |
|
|
|
// Converting Int or Real to bool |
|
template<class O> |
|
class Convert2Struct<bool,O> |
|
{ |
|
public: |
|
bool operator ()(const O* q, bool* suc) const {return q->Value()!=0;} |
|
}; |
|
// Converting String to bool |
|
template<> |
|
class Convert2Struct<bool,ObjectString> |
|
{ |
|
public: |
|
bool operator ()(const ObjectString* q, bool* suc) 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; |
|
*suc=false; |
|
return false; |
|
} |
|
}; |
|
|
|
// Get string |
|
template<> |
|
class Convert2Struct<std::string,ObjectString> |
|
{ |
|
public: |
|
std::string operator ()(const ObjectString* q, bool* suc) const {return q->Value();} |
|
}; |
|
|
|
// This class search parameter with specified names in the list, which may be converted to Struct. |
|
// If SearchByType is true, additionaly search unnamed parameter of corresponding Object class (ObjectGMTClass<Struct> for gmt_struct-derived types, for example). |
|
// Additionally, Policies can be used to check correctness of found parameter. |
|
template<class Struct, bool SearchByType=true, class... Policies> |
|
class SearchParameter; |
|
template<class Struct, bool SearchByType=true, class... Policies> |
|
class SearchParameterWDef; |
|
|
|
// Generic type storage class |
|
template<class Struct,class... Types> |
|
class gTypeStorage |
|
{ |
|
template<class O> class Convertor: public Convert2Struct<Struct, O> {}; // Conversion type |
|
public: |
|
typedef Base2Something<Convertor,Types...> Base2Type; |
|
typedef SearchParameter<Struct,false> BaseM2Type; |
|
typedef SearchParameter<Struct,true> BaseMT2Type; |
|
typedef SearchParameterWDef<Struct,false> BaseMD2Type; |
|
typedef SearchParameterWDef<Struct,true> BaseMTD2Type; |
|
}; |
|
// Specific type storage class |
|
template<class Struct> |
|
class TypeStorage; |
|
|
|
// Default ObjectList converter |
|
template<class Struct> |
|
class Convert2Struct<Struct, ObjectList> |
|
{ |
|
public: |
|
template<class... Args> |
|
Struct operator()(const ObjectList* o, bool* suc, Args... args) const |
|
{ |
|
Struct s; |
|
if(o->Size()!=1) {*suc=false; return s;} |
|
typename TypeStorage<Struct>::Base2Type a(o,0); |
|
s=a(suc,args...); |
|
return s; |
|
} |
|
}; |
|
|
|
// Helper struct for class SearchParameter |
|
template<class Struct, bool check> |
|
// Search function for non-gmt_struct types do nothing |
|
struct SearchHelper {void operator()(const ObjectList* input, Struct* s, bool* exist, bool* ok) const {}}; |
|
template<class Struct> |
|
// Search function for gmt_struct types find ObjectGMTClass<Struct> in list |
|
struct SearchHelper<Struct,true> |
|
{ |
|
void operator()(const ObjectList* input, Struct* s, bool* exist, bool* ok) const |
|
{ |
|
for(ObjectList::IndexType i=0;i<input->Size();i++) |
|
{ |
|
OBType<ObjectGMTClass<Struct> > obj(input->At(i)); |
|
if(obj) |
|
{ |
|
if(*exist) {*ok=false; break;} // Object already found |
|
*s=obj->Data(); |
|
*exist=true; |
|
} |
|
} |
|
} |
|
}; |
|
|
|
// Definition without policies |
|
template<class Struct, bool SearchByType> |
|
class SearchParameter<Struct,SearchByType> |
|
{ |
|
typedef typename TypeStorage<Struct>::Base2Type Base2Struct; |
|
protected: |
|
bool exist; // There is at least one parameter with given names |
|
bool ok; // True if conversion to corresponding structure was successful and there is only one parameter with given names |
|
Struct val; |
|
SearchParameter() = delete; |
|
SearchParameter(SearchParameter&&) = delete; |
|
SearchParameter(SearchParameter&) = delete; |
|
public: |
|
// Recursive constructor |
|
template<class... Args> |
|
SearchParameter(const ObjectList* input, const std::string& name, Args... args):SearchParameter(input,args...) |
|
{ |
|
if(ok) |
|
{ |
|
Base2Struct a(input,name); |
|
if(exist && a.Exist()) ok=false; |
|
else if(a.Exist()) |
|
{ |
|
exist=true; |
|
ok=true; |
|
val=a(&ok); |
|
} |
|
} |
|
} |
|
// Bottom of recursion |
|
SearchParameter(const ObjectList* input):exist(false),ok(true) {SearchHelper<Struct,SearchByType>()(input,&val,&exist,&ok);} |
|
// Search by index |
|
SearchParameter(const ObjectList* input, const ObjectList::IndexType i):exist(false),ok(true) |
|
{ |
|
Base2Struct a(input,i); |
|
if(a.Exist()) |
|
{ |
|
exist=true; |
|
val=a(&ok); |
|
} |
|
} |
|
Struct operator()(bool* suc) const |
|
{ |
|
if(!ok || !exist) *suc=false; |
|
return val; |
|
} |
|
Struct operator()(bool* ex, bool* suc) const |
|
{ |
|
*ex=exist; |
|
if(!ok || !exist) *suc=false; |
|
return val; |
|
} |
|
bool Exist() const {return exist;} |
|
}; |
|
|
|
// Definition with policies |
|
template<class Struct, bool SearchByType, class Policy, class... Policies> |
|
class SearchParameter<Struct,SearchByType,Policy,Policies...>: public SearchParameter<Struct,SearchByType,Policies...> |
|
{ |
|
SearchParameter() = delete; |
|
SearchParameter(SearchParameter&&) = delete; |
|
SearchParameter(SearchParameter&) = delete; |
|
public: |
|
using SearchParameter<Struct,SearchByType,Policies...>::ok; |
|
using SearchParameter<Struct,SearchByType,Policies...>::exist; |
|
// Recursive constructor |
|
template<class... Args> |
|
SearchParameter(const ObjectList* input, Args... args):SearchParameter<Struct,SearchByType,Policies...>(input,args...) {} |
|
Struct operator()(bool* suc) const |
|
{ |
|
return Policy()(SearchParameter<Struct,SearchByType,Policies...>::operator()(suc),suc); |
|
} |
|
Struct operator()(bool* ex, bool* suc) const |
|
{ |
|
return Policy()(SearchParameter<Struct,SearchByType,Policies...>::operator()(suc),suc); |
|
} |
|
}; |
|
|
|
// SearchParameter with default value |
|
template<class Struct, bool SearchByType, class... Policies> |
|
class SearchParameterWDef: protected SearchParameter<Struct,SearchByType,Policies...> |
|
{ |
|
typedef SearchParameter<Struct,SearchByType,Policies...> SP; |
|
SearchParameterWDef() = delete; |
|
SearchParameterWDef(SearchParameterWDef&&) = delete; |
|
SearchParameterWDef(SearchParameterWDef&) = delete; |
|
public: |
|
template<class... Args> |
|
SearchParameterWDef(const ObjectList* input, const Struct& def, Args... args):SP(input,args...) |
|
{ |
|
if(!SP::exist) SP::val=def; |
|
SP::exist=true; |
|
} |
|
Struct operator()(bool* suc) const {return SP::operator()(suc);} |
|
Struct operator()(bool* ex, bool* suc) const {return SP::operator()(ex,suc);} |
|
bool Exist() const {return true;} |
|
}; |
|
|
|
// SearchParameter with default value setted as class |
|
template<class Struct, class DefClass, bool SearchByType=false, class... Policies> |
|
class SearchParameterWDefO: protected SearchParameter<Struct,SearchByType,Policies...> |
|
{ |
|
typedef SearchParameter<Struct,SearchByType,Policies...> SP; |
|
SearchParameterWDefO() = delete; |
|
SearchParameterWDefO(SearchParameterWDefO&&) = delete; |
|
SearchParameterWDefO(SearchParameterWDefO&) = delete; |
|
public: |
|
template<class... Args> |
|
SearchParameterWDefO(const ObjectList* input, Args... args):SP(input,args...) |
|
{ |
|
if(!SP::exist) SP::val=DefClass()(); |
|
SP::exist=true; |
|
} |
|
Struct operator()(bool* suc) const {return SP::operator()(suc);} |
|
Struct operator()(bool* ex, bool* suc) const {return SP::operator()(ex,suc);} |
|
bool Exist() const {return true;} |
|
}; |
|
|
|
// Class for default double value |
|
// We use rational representation of floating point number, because double type values not allowed as template parameter |
|
template<int32_t num=0, uint32_t denum=1> |
|
class DoubleDefaultVal |
|
{ |
|
DoubleDefaultVal(DoubleDefaultVal&&) = delete; |
|
DoubleDefaultVal(DoubleDefaultVal&) = delete; |
|
public: |
|
DoubleDefaultVal(){}; |
|
double operator()() const {return static_cast<double>(num)/denum;} |
|
}; |
|
|
|
// Definitions for double |
|
template<> class TypeStorage<double>: public gTypeStorage<double,ObjectReal,ObjectInt,ObjectString> {}; |
|
typedef TypeStorage<double>::Base2Type Base2Double; |
|
typedef TypeStorage<double>::BaseM2Type BaseM2Double; |
|
typedef TypeStorage<double>::BaseMT2Type BaseMT2Double; |
|
typedef TypeStorage<double>::BaseMD2Type BaseMD2Double; |
|
typedef TypeStorage<double>::BaseMTD2Type BaseMTD2Double; |
|
// Definitions for bool |
|
template<> class TypeStorage<bool>: public gTypeStorage<bool,ObjectInt,ObjectReal,ObjectString> {}; |
|
typedef TypeStorage<bool>::Base2Type Base2Bool; |
|
typedef TypeStorage<bool>::BaseM2Type BaseM2Bool; |
|
typedef TypeStorage<bool>::BaseMT2Type BaseMT2Bool; |
|
typedef TypeStorage<bool>::BaseMD2Type BaseMD2Bool; |
|
typedef TypeStorage<bool>::BaseMTD2Type BaseMTD2Bool; |
|
// Definitions for string |
|
template<> class TypeStorage<std::string>: public gTypeStorage<std::string,ObjectString> {}; |
|
typedef TypeStorage<std::string>::Base2Type Base2String; |
|
typedef TypeStorage<std::string>::BaseM2Type BaseM2String; |
|
typedef TypeStorage<std::string>::BaseMT2Type BaseMT2String; |
|
typedef TypeStorage<std::string>::BaseMD2Type BaseMD2String; |
|
typedef TypeStorage<std::string>::BaseMTD2Type BaseMTD2String; |
|
|
|
// Definitions for ObjectGMTCoord |
|
template<> class TypeStorage<struct gmt_coord>: public gTypeStorage<struct gmt_coord,ObjectReal,ObjectInt,ObjectString,ObjectGMTCoord,ObjectList> {}; |
|
typedef TypeStorage<struct gmt_coord>::Base2Type Base2Coord; |
|
typedef TypeStorage<struct gmt_coord>::BaseM2Type BaseM2Coord; |
|
typedef TypeStorage<struct gmt_coord>::BaseMT2Type BaseMT2Coord; |
|
typedef TypeStorage<struct gmt_coord>::BaseMD2Type BaseMD2Coord; |
|
typedef TypeStorage<struct gmt_coord>::BaseMTD2Type BaseMTD2Coord; |
|
// Definitions for ObjectGMTRegion |
|
template<> class TypeStorage<struct gmt_region>: public gTypeStorage<struct gmt_region,ObjectList,ObjectString,ObjectGMTRegion> {}; |
|
typedef TypeStorage<struct gmt_region>::Base2Type Base2Region; |
|
typedef TypeStorage<struct gmt_region>::BaseM2Type BaseM2Region; |
|
typedef TypeStorage<struct gmt_region>::BaseMT2Type BaseMT2Region; |
|
typedef TypeStorage<struct gmt_region>::BaseMD2Type BaseMD2Region; |
|
typedef TypeStorage<struct gmt_region>::BaseMTD2Type BaseMTD2Region; |
|
// Definitions for ObjectGMTProjection |
|
template<> class TypeStorage<struct gmt_projection>: public gTypeStorage<struct gmt_projection,ObjectList,ObjectGMTProjection> {}; |
|
typedef TypeStorage<struct gmt_projection>::Base2Type Base2Projection; |
|
typedef TypeStorage<struct gmt_projection>::BaseM2Type BaseM2Projection; |
|
typedef TypeStorage<struct gmt_projection>::BaseMT2Type BaseMT2Projection; |
|
typedef TypeStorage<struct gmt_projection>::BaseMD2Type BaseMD2Projection; |
|
typedef TypeStorage<struct gmt_projection>::BaseMTD2Type BaseMTD2Projection; |
|
// Definitions for ObjectGMTColor |
|
template<> class TypeStorage<struct gmt_color>: public gTypeStorage<struct gmt_color,ObjectList,ObjectString,ObjectReal,ObjectInt,ObjectGMTColor> {}; |
|
typedef TypeStorage<struct gmt_color>::Base2Type Base2Color; |
|
typedef TypeStorage<struct gmt_color>::BaseM2Type BaseM2Color; |
|
typedef TypeStorage<struct gmt_color>::BaseMT2Type BaseMT2Color; |
|
typedef TypeStorage<struct gmt_color>::BaseMD2Type BaseMD2Color; |
|
typedef TypeStorage<struct gmt_color>::BaseMTD2Type BaseMTD2Color; |
|
// Definitions for ObjectGMTDash |
|
template<> class TypeStorage<struct gmt_dash>: public gTypeStorage<struct gmt_dash,ObjectString,ObjectGMTDash> {}; |
|
typedef TypeStorage<struct gmt_dash>::Base2Type Base2Dash; |
|
typedef TypeStorage<struct gmt_dash>::BaseM2Type BaseM2Dash; |
|
typedef TypeStorage<struct gmt_dash>::BaseMT2Type BaseMT2Dash; |
|
typedef TypeStorage<struct gmt_dash>::BaseMD2Type BaseMD2Dash; |
|
typedef TypeStorage<struct gmt_dash>::BaseMTD2Type BaseMTD2Dash; |
|
// Definitions for ObjectGMTPen |
|
template<> class TypeStorage<struct gmt_pen>: public gTypeStorage<struct gmt_pen,ObjectList,ObjectString,ObjectReal,ObjectInt,ObjectGMTPen> {}; |
|
typedef TypeStorage<struct gmt_pen>::Base2Type Base2Pen; |
|
typedef TypeStorage<struct gmt_pen>::BaseM2Type BaseM2Pen; |
|
typedef TypeStorage<struct gmt_pen>::BaseMT2Type BaseMT2Pen; |
|
typedef TypeStorage<struct gmt_pen>::BaseMD2Type BaseMD2Pen; |
|
typedef TypeStorage<struct gmt_pen>::BaseMTD2Type BaseMTD2Pen; |
|
// Definitions for ObjectGMTFont |
|
template<> class TypeStorage<struct gmt_font>: public gTypeStorage<struct gmt_font,ObjectList,ObjectString,ObjectReal,ObjectInt,ObjectGMTFont> {}; |
|
typedef TypeStorage<struct gmt_font>::Base2Type Base2Font; |
|
typedef TypeStorage<struct gmt_font>::BaseM2Type BaseM2Font; |
|
typedef TypeStorage<struct gmt_font>::BaseMT2Type BaseMT2Font; |
|
typedef TypeStorage<struct gmt_font>::BaseMD2Type BaseMD2Font; |
|
typedef TypeStorage<struct gmt_font>::BaseMTD2Type BaseMTD2Font; |
|
// Definitions for ObjectGMTLayer |
|
template<> class TypeStorage<struct gmt_layer>: public gTypeStorage<struct gmt_layer,ObjectList,ObjectGMTLayer> {}; |
|
typedef TypeStorage<struct gmt_layer>::Base2Type Base2Layer; |
|
typedef TypeStorage<struct gmt_layer>::BaseM2Type BaseM2Layer; |
|
typedef TypeStorage<struct gmt_layer>::BaseMT2Type BaseMT2Layer; |
|
typedef TypeStorage<struct gmt_layer>::BaseMD2Type BaseMD2Layer; |
|
typedef TypeStorage<struct gmt_layer>::BaseMTD2Type BaseMTD2Layer; |
|
|
|
// 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) const |
|
{ |
|
struct gmt_region r; |
|
auto size=input->Size(); |
|
bool suc=true; |
|
|
|
if(1==size) // Cases 1, 2 and 3 |
|
{ |
|
Base2Region region(input,0); |
|
r=region(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
return r; |
|
} |
|
|
|
// Case 4 |
|
{ |
|
std::string type; |
|
bool typeexist=false; |
|
{ |
|
Base2String t(input,"type"); |
|
if(t.Exist()) |
|
{ |
|
type=t(&suc); |
|
tolower(type); |
|
if(!suc) goto fail; // Conversion failed |
|
typeexist=true; |
|
} |
|
else type="nobbox"; |
|
} |
|
if(r.Convert(type)) return r; // type is one of "global*" string, we can return, becuse upd is irrelevant |
|
|
|
bool upd; |
|
{ |
|
BaseMT2Region updarg(input,"r","region"); |
|
r=updarg(&upd,&suc); |
|
if(upd && !suc) goto fail; // Conversion failed or too many arguments |
|
suc=true; |
|
} |
|
|
|
Base2Coord ixb(input,"xb"), ixe(input,"xe"), iyb(input,"yb"), iye(input,"ye"); |
|
if(!(typeexist || ixb.Exist() || ixe.Exist() || iyb.Exist() || iye.Exist() || upd)) goto case5; // No named parameters, no update mode, possibly case 5 |
|
struct gmt_coord xb,yb,xe,ye; |
|
bool isbbox=upd?(gmt_region::BBOX==r.type):false; |
|
|
|
if(typeexist) |
|
{ |
|
if("bbox"==type) isbbox=true; |
|
if("nobbox"==type) isbbox=false; |
|
if("bbox"!=type && "nobbox"!=type) goto fail; // Unknown type |
|
} |
|
|
|
if(upd) |
|
{ |
|
if(!ixb.Exist()) xb=r.xb; |
|
if(!ixe.Exist()) xe=r.xe; |
|
if(!iyb.Exist()) yb=r.yb; |
|
if(!iye.Exist()) ye=r.ye; |
|
} |
|
else suc=suc && ixb.Exist() && ixe.Exist() && iyb.Exist() && iye.Exist(); // In "new" mode all parameters must exists |
|
if(ixb.Exist()) xb=ixb(&suc); |
|
if(ixe.Exist()) xe=ixe(&suc); |
|
if(iyb.Exist()) yb=iyb(&suc); |
|
if(iye.Exist()) ye=iye(&suc); |
|
if(!suc) goto fail; // Something wrong |
|
if(!r.Convert(xb,xe,yb,ye,isbbox)) goto fail; // Conversion failed |
|
return r; // Case 3 with all parameters |
|
} |
|
|
|
case5: |
|
// Case 5 |
|
if(4==size || 5==size) |
|
{ |
|
bool isbbox=false; |
|
if(5==size) |
|
{ |
|
Base2String type(input,4); |
|
std::string str=type(&suc); |
|
if(!suc) goto fail; // Wrong parameter |
|
tolower(str); |
|
if("bbox"!=str || "nobbox"!=str) goto fail; // Unknown fifth parameter |
|
if("bbox"==str) isbbox=true; |
|
} |
|
Base2Coord ixb(input,0), ixe(input,(isbbox?2:1)), iyb(input,(isbbox?1:2)), iye(input,3); |
|
struct gmt_coord xb=ixb(&suc),yb=iyb(&suc),xe=ixe(&suc),ye=iye(&suc); |
|
if(suc) |
|
{ |
|
if(!r.Convert(xb,xe,yb,ye,isbbox)) 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) const |
|
{ |
|
typedef SearchParameter<double,false,PMin<0> > BaseM2Nonneg; |
|
struct gmt_projection p; |
|
auto size=input->Size(); |
|
bool suc=true; |
|
|
|
if(1==size) // Cases 1, and 2 |
|
{ |
|
Base2Projection proj(input,0); |
|
bool suc=true; |
|
p=proj(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
return p; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
bool upd; |
|
bool changetype=false; |
|
{ |
|
BaseMT2Projection updarg(input,"p","proj","projection"); |
|
p=updarg(&upd,&suc); |
|
if(upd && !suc) goto fail; // Conversion failed or too many arguments |
|
suc=true; |
|
} |
|
|
|
// Try to set type of projection |
|
{ |
|
BaseM2String type(input,"t","type","projtype"); |
|
if(!(type.Exist() || upd)) goto case4; // No named parameter, not update mode, go to case 4 |
|
// Check on redundant parameters |
|
if(type.Exist()) |
|
{ |
|
std::string typestr=type(&suc); |
|
if(!suc) goto fail; // Wrong parameter type |
|
if(!p.SetType(typestr)) goto fail; // Incorrect projection type |
|
changetype=true; |
|
} |
|
} |
|
|
|
// We need the region |
|
{ |
|
BaseMT2Region region(input,"r","region"); |
|
if(!(region.Exist() || upd)) goto fail; // Region must be defined in "new" mode |
|
if(region.Exist()) p.region=region(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
} |
|
|
|
// Get parameters of projection |
|
switch(p.proj) |
|
{ |
|
case(gmt_projection::XY): // x Parameter height (by default equal width) |
|
{ |
|
BaseM2Nonneg height(input,"height","h"); |
|
if(height.Exist()) |
|
{ |
|
bool suc=true; |
|
p.x.height=height(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else |
|
{ |
|
BaseM2Nonneg width(input,"width","w"); |
|
if(!width.Exist() && changetype) p.x.height=gmt_projection::default_width; // We ignore case when parameter width exists but have wrong type. It will be handled later. |
|
else |
|
{ |
|
bool suc=true; |
|
p.x.height=width(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
} |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQU): // q Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
Base2Coord cmer(input,"cmer"), stpar(input,"stpar"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.q.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.q.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.q.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.q.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
break; |
|
} |
|
case(gmt_projection::MERCATOR): // m Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
Base2Coord cmer(input,"cmer"), stpar(input,"stpar"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.m.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.m.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.m.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.m.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
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) |
|
{ |
|
Base2Coord cmer(input,"cmer"), orlat(input,"orlat"); |
|
Base2Double scale(input,"scale"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.t.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(orlat.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.orlat=orlat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.t.orlat.Convert(0.0); |
|
if(scale.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.scale=scale(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.t.scale=1.0; |
|
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). |
|
{ |
|
Base2Coord clon(input,"clon"), clat(input,"clat"); |
|
Base2Coord azimuth(input,"azimuth"), eqlon(input,"eqlon"), eqlat(input,"eqlat"), polelon(input,"polelon"), polelat(input,"polelat"); |
|
if(changetype) p.o.type=gmt_projection::OType::NOTDEF; |
|
if(clon.Exist()) |
|
{ |
|
bool suc=true; |
|
p.o.clon=clon(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.o.clon.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(clat.Exist()) |
|
{ |
|
bool suc=true; |
|
p.o.clat=clat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.o.clat.Convert((p.region.yb+p.region.ye)*0.5); |
|
// Variant 1 |
|
if(azimuth) |
|
{ |
|
bool suc=(gmt_projection::OType::NOTDEF==p.o.type); // If projection subtype already defined, this is an error |
|
p.o.type=gmt_projection::OType::A; |
|
p.o.azimuth=azimuth(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
if(eqlon && eqlat) |
|
{ |
|
bool suc=(gmt_projection::OType::NOTDEF==p.o.type); // If projection subtype already defined, this is an error |
|
p.o.type=gmt_projection::OType::B; |
|
p.o.eqlon=eqlon(&suc); |
|
p.o.eqlat=eqlat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
if(polelon && polelat) |
|
{ |
|
bool suc=(gmt_projection::OType::NOTDEF==p.o.type); // If projection subtype already defined, this is an error |
|
p.o.type=gmt_projection::OType::C; |
|
p.o.polelon=polelon(&suc); |
|
p.o.polelat=polelat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
if(gmt_projection::OType::NOTDEF==p.o.type) 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. |
|
{ |
|
Base2Coord clon(input,"clon"), clat(input,"clat"); |
|
if(clon.Exist()) |
|
{ |
|
bool suc=true; |
|
p.c.clon=clon(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.c.clon.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(clat.Exist()) |
|
{ |
|
bool suc=true; |
|
p.c.clat=clat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.c.clat.Convert((p.region.yb+p.region.ye)*0.5); |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region) |
|
{ |
|
Base2Coord cmer(input,"cmer"), stpar(input,"stpar"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.y.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.y.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.y.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.y.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
break; |
|
} |
|
case(gmt_projection::MILLER): // j Parameters: central meridian (cmer, default is center of region) |
|
{ |
|
Base2Coord cmer(input,"cmer"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.j.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.j.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
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) |
|
{ |
|
Base2Coord cmer(input,"cmer"), stpar(input,"stpar"); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.cyl_stere.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.cyl_stere.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.cyl_stere.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else if(changetype) p.cyl_stere.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
break; |
|
} |
|
default: goto fail; // Unknown projection |
|
} |
|
|
|
// Try to find width parameter |
|
if(!upd) p.width=p.default_width; |
|
{ |
|
BaseM2Nonneg w(input,"width","w"),h(input,"height","h"); |
|
bool suc=true; |
|
if(w.Exist()) // width is present |
|
{ |
|
p.width=w(&suc); |
|
if(!suc) goto fail; // Parameter width exists, but can't be converted to double |
|
if(!ProjectionRealSize(p)) goto fail; // Something go wrong with determining real dimensions |
|
} |
|
else if(h.Exist()) // width is not present, but height is present |
|
{ |
|
double hval=h(&suc); |
|
if(!suc) goto fail; // Parameter height exists, but can't be converted to double |
|
if(gmt_projection::XY==p.proj) p.width=hval; // For decart projection we use height as width if width is not specified |
|
if(!ProjectionRealSize(p,hval)) goto fail; // Something go wrong with determining real dimensions |
|
} |
|
else // No width, no height, using default or old width |
|
if(!ProjectionRealSize(p)) goto fail; // Something go wrong with determining real dimensions |
|
} |
|
return p; // All parameters setted |
|
} |
|
|
|
case4: |
|
|
|
// Case 4 |
|
if(size>=3) |
|
{ |
|
// First argument, try to set type of projection |
|
{ |
|
Base2String type(input,0); |
|
bool suc=true; |
|
std::string typestr; |
|
typestr=type(&suc); |
|
if(!suc) goto fail; // No type - no projection |
|
if(!p.SetType(typestr)) goto fail; // Unknown type - no projection |
|
} |
|
// Second argument, set up width |
|
{ |
|
Base2Double w(input,1); |
|
bool suc=true; |
|
p.width=w(&suc); |
|
if(!suc) goto fail; // Conversion failed, no width |
|
} |
|
// Third argument, set up region |
|
{ |
|
Base2Region reg(input,2); |
|
bool suc=true; |
|
p.region=reg(&suc); |
|
if(!suc) goto fail; // Conversion failed, no region |
|
} |
|
|
|
// Projection specific parameters |
|
switch(p.proj) |
|
{ |
|
case(gmt_projection::XY): // x Parameter 4 is height (by default equal width) |
|
{ |
|
Base2Double height(input,3); |
|
if(height.Exist()) |
|
{ |
|
bool suc=true; |
|
p.x.height=height(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.x.height=p.width; |
|
if(size>4) goto fail; // Unknown parameter(s) |
|
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) |
|
{ |
|
Base2Coord cmer(input,3), stpar(input,4); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.q.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.q.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.q.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.q.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
if(size>5) goto fail; // Unknown parameter(s) |
|
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) |
|
{ |
|
Base2Coord cmer(input,3), stpar(input,4); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.m.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.m.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.m.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.m.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
if(size>5) goto fail; // Unknown parameter(s) |
|
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) |
|
{ |
|
Base2Coord cmer(input,3), orlat(input,4); |
|
Base2Double scale(input,5); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.t.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(orlat.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.orlat=orlat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.t.orlat.Convert(0.0); |
|
if(scale.Exist()) |
|
{ |
|
bool suc=true; |
|
p.t.scale=scale(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.t.scale=1.0; |
|
if(size>6) goto fail; // Unknown parameter(s) |
|
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). |
|
{ |
|
if(size<4) goto fail; // Insufficient data for this projection |
|
OBType<ObjectString> stype(input->At(3)); |
|
if(!stype) goto fail; // Incorrect parameter type |
|
std::string subtype=stype->Value(); |
|
tolower(subtype); |
|
Base2Coord clon(input,4), clat(input,5); |
|
Base2Coord azimuth(input,6), eqlon(input,6), eqlat(input,7), polelon(input,6), polelat(input,7); |
|
p.o.type=gmt_projection::OType::NOTDEF; |
|
{ |
|
bool suc=true; |
|
p.o.clon=clon(&suc); |
|
p.o.clat=clat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
// Variant 1 |
|
if("a"==subtype || "azimuth"==subtype) |
|
{ |
|
p.o.type=gmt_projection::OType::A; |
|
bool suc=true; |
|
p.o.azimuth=azimuth(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
if(size>7) goto fail; // Unknown parameter(s) |
|
} |
|
if("b"==subtype || "equator"==subtype) |
|
{ |
|
p.o.type=gmt_projection::OType::B; |
|
bool suc=true; |
|
p.o.eqlon=eqlon(&suc); |
|
p.o.eqlat=eqlat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
if(size>8) goto fail; // Unknown parameter(s) |
|
} |
|
if("c"==subtype || "pole"==subtype) |
|
{ |
|
p.o.type=gmt_projection::OType::C; |
|
bool suc=true; |
|
p.o.polelon=polelon(&suc); |
|
p.o.polelat=polelat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
if(size>8) goto fail; // Unknown parameter(s) |
|
} |
|
if(gmt_projection::OType::NOTDEF==p.o.type) goto fail; // Insufficient data for this projection |
|
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. |
|
{ |
|
Base2Coord clon(input,3), clat(input,4); |
|
if(clon.Exist()) |
|
{ |
|
bool suc=true; |
|
p.c.clon=clon(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.c.clon.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(clat.Exist()) |
|
{ |
|
bool suc=true; |
|
p.c.clat=clat(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.c.clat.Convert((p.region.yb+p.region.ye)*0.5); |
|
if(size>5) goto fail; // Unknown parameter(s) |
|
break; |
|
} |
|
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (4, default is center of region), standart parallel (5, default is center of region) |
|
{ |
|
Base2Coord cmer(input,3), stpar(input,4); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.y.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.y.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.y.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.y.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
if(size>5) goto fail; // Unknown parameter(s) |
|
break; |
|
} |
|
case(gmt_projection::MILLER): // j Parameters: central meridian (4, default is center of region) |
|
{ |
|
Base2Coord cmer(input,3); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.j.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.j.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(size>4) goto fail; // Unknown parameter(s) |
|
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) |
|
{ |
|
Base2Coord cmer(input,3), stpar(input,4); |
|
if(cmer.Exist()) |
|
{ |
|
bool suc=true; |
|
p.cyl_stere.cmer=cmer(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.cyl_stere.cmer.Convert((p.region.xb+p.region.xe)*0.5); |
|
if(stpar.Exist()) |
|
{ |
|
bool suc=true; |
|
p.cyl_stere.stpar=stpar(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
else p.cyl_stere.stpar.Convert((p.region.yb+p.region.ye)*0.5); |
|
if(size>5) goto fail; // Unknown parameter(s) |
|
break; |
|
} |
|
default: goto fail; // Unknown projection |
|
} |
|
if(ProjectionRealSize(p)) return p; |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return p; // Something go wrong |
|
} |
|
}; |
|
|
|
// Helper types |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0>,PMax<255> > Base2RGB; |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0>,PMax<360> > Base2Hue; |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0>,PMax<1 > > Base2SV; |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0>,PMax<100> > Base2CMYK; |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0>,PMax<100> > Base2Transp; |
|
|
|
typedef SearchParameter<double,false,PMin<0>,PMax<255> > BaseM2RGB; |
|
typedef SearchParameter<double,false,PMin<0>,PMax<360> > BaseM2Hue; |
|
typedef SearchParameter<double,false,PMin<0>,PMax<1 > > BaseM2SV; |
|
typedef SearchParameter<double,false,PMin<0>,PMax<100> > BaseM2CMYK; |
|
typedef SearchParameter<double,false,PMin<0>,PMax<100> > BaseM2Transp; |
|
|
|
// 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) const |
|
{ |
|
struct gmt_color c; |
|
auto size=input->Size(); |
|
|
|
if(1==size) // Cases 1, 2 and 4 |
|
{ |
|
Base2Color color(input,0); |
|
bool suc=true; |
|
c=color(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
return c; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
bool cmodset=false; |
|
bool upd; |
|
{ |
|
BaseMT2Color updarg(input,"color"); |
|
bool suc=true; |
|
c=updarg(&upd,&suc); |
|
if(upd && !suc) goto fail; // Conversion failed or too many arguments |
|
} |
|
if(!upd) |
|
{ |
|
// default color is black |
|
c.transparency=0; |
|
c.model=gmt_color::GRAY; |
|
c.gray=0.0; |
|
} |
|
|
|
{ |
|
BaseM2Transp t(input,"t","transp","transparency"); |
|
if(t.Exist()) |
|
{ |
|
bool suc=true; |
|
c.transparency=t(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
} |
|
} |
|
|
|
// GRAY |
|
{ |
|
BaseM2RGB g(input,"gray","grey"); |
|
if(g.Exist()) |
|
{ |
|
if(cmodset) goto fail; // Model already set |
|
bool suc=true; |
|
c.model=gmt_color::GRAY; |
|
c.gray=g(&suc); // Update mode ignored in this case |
|
if(!suc) goto fail; // Parsing error |
|
cmodset=true; |
|
} |
|
} |
|
|
|
// RGB |
|
{ |
|
BaseM2RGB r(input,"r","red"), g(input,"g","green"), b(input,"b","blue"); |
|
if(r.Exist() || g.Exist() || b.Exist()) |
|
{ |
|
if(cmodset) goto fail; // Model already set |
|
bool suc=true; |
|
c.ToRGB(); |
|
if(r.Exist()) c.r=r(&suc); |
|
if(g.Exist()) c.g=g(&suc); |
|
if(b.Exist()) c.b=b(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
cmodset=true; |
|
} |
|
} |
|
|
|
// HSV |
|
{ |
|
BaseM2Hue h(input,"h","hue"); |
|
BaseM2SV s(input,"s","sat","saturation"), v(input,"v","val","value"); |
|
if(h.Exist() || s.Exist() || v.Exist()) |
|
{ |
|
if(cmodset) goto fail; // Model already set |
|
bool suc=true; |
|
c.ToHSV(); |
|
if(h.Exist()) c.hue=h(&suc); |
|
if(s.Exist()) c.saturation=s(&suc); |
|
if(v.Exist()) c.value=v(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
cmodset=true; |
|
} |
|
} |
|
|
|
// CMYK |
|
{ |
|
BaseM2CMYK cc(input,"c","cyan"), m(input,"m","magenta"), y(input,"y","yellow"), k(input,"k","black"); |
|
if(cc.Exist() || m.Exist() || y.Exist() || k.Exist()) |
|
{ |
|
if(cmodset) goto fail; // Model already set |
|
bool suc=true; |
|
c.ToCMYK(); |
|
if(cc.Exist()) c.cyan=cc(&suc); |
|
if(m.Exist()) c.magenta=m(&suc); |
|
if(y.Exist()) c.yellow=y(&suc); |
|
if(k.Exist()) c.black=k(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
cmodset=true; |
|
} |
|
} |
|
if(cmodset || upd) return c; // Color created or updated |
|
} |
|
|
|
// Case 5 |
|
if(3==size) |
|
{ |
|
Base2RGB r(input,0), g(input,1), b(input,2); |
|
c.model=gmt_color::RGB; |
|
bool suc=true; |
|
c.r=r(&suc); |
|
c.g=g(&suc); |
|
c.b=b(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
return c; |
|
} |
|
|
|
// Case 6 |
|
if(4==size) |
|
{ |
|
Base2CMYK cc(input,0), m(input,1), y(input,2), k(input,3); |
|
c.model=gmt_color::CMYK; |
|
bool suc=true; |
|
c.cyan=cc(&suc); |
|
c.magenta=m(&suc); |
|
c.yellow=y(&suc); |
|
c.black=k(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
return c; |
|
} |
|
|
|
fail: |
|
*issuc=false; |
|
return c; // Something go wrong |
|
} |
|
}; |
|
|
|
// Helper types |
|
typedef SearchParameterWDefO<double,DoubleDefaultVal<>,false,PMin<0> > Base2Width; |
|
typedef SearchParameter<double,false,PMin<0> > BaseM2Width; |
|
|
|
// 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) const |
|
{ |
|
struct gmt_pen p; |
|
auto size=input->Size(); |
|
|
|
if(1==size) // Cases 1, 2 and 4 |
|
{ |
|
Base2Pen pen(input,0); |
|
bool suc=true; |
|
p=pen(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
return p; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
bool casevalid=false; |
|
bool upd; |
|
{ |
|
BaseMT2Pen updarg(input,"pen","p"); |
|
bool suc=true; |
|
p=updarg(&upd,&suc); |
|
if(upd && !suc) goto fail; // Conversion failed or too many arguments |
|
} |
|
|
|
if(!upd) |
|
{ |
|
// default pen is solid black 1mm width |
|
p.width=gmt_pen::default_width; |
|
p.color.Convert(0); |
|
p.dash.Clear(); |
|
} |
|
|
|
{ |
|
BaseM2Width w(input,"w","width"); |
|
if(w.Exist()) |
|
{ |
|
bool suc=true; |
|
p.width=w(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
casevalid=true; |
|
} |
|
} |
|
|
|
// Color |
|
{ |
|
BaseMT2Color color(input,"color","c"); |
|
if(color.Exist()) |
|
{ |
|
bool suc=true; |
|
p.color=color(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
casevalid=true; |
|
} |
|
} |
|
|
|
// Dash |
|
{ |
|
BaseMT2Dash dash(input,"dash","d"); |
|
if(dash.Exist()) |
|
{ |
|
bool suc=true; |
|
p.dash=dash(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
p.dash.width=p.width; |
|
casevalid=true; |
|
} |
|
} |
|
|
|
if(casevalid || upd) return p; // Pen created or updated |
|
} |
|
|
|
// Case 5 and 6 |
|
if(2==size || 3==size) |
|
{ |
|
Base2Width w(input,0); |
|
Base2Color c(input,1); |
|
Base2Dash d(input,2); |
|
bool suc=true; |
|
p.width=w(&suc); |
|
p.color=c(&suc); |
|
if(!suc) goto fail; // Something wrong |
|
p.dash=d(&suc,p.width); |
|
if(!suc) goto fail; // Something wrong |
|
return p; |
|
} |
|
|
|
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) const |
|
{ |
|
struct gmt_font f; |
|
auto size=input->Size(); |
|
|
|
if(1==size) // Cases 1, 2, 4 and 5 |
|
{ |
|
Base2Font font(input,0); |
|
bool suc=true; |
|
f=font(&suc); |
|
if(!suc) goto fail; // Conversion failed |
|
return f; |
|
} |
|
|
|
// Case 3 |
|
{ |
|
bool casevalid=false; |
|
bool upd; |
|
{ |
|
BaseMT2Font updarg(input,"font"); |
|
bool suc=true; |
|
f=updarg(&upd,&suc); |
|
if(upd && !suc) goto fail; // Conversion failed or too many arguments |
|
} |
|
|
|
if(!upd) |
|
{ |
|
// default font is Times-Roman, 12pt, black |
|
f.size=gmt_font::default_size; |
|
f.color.Convert(0); |
|
f.family=gmt_font::default_family; |
|
} |
|
|
|
// Size |
|
{ |
|
BaseM2Width s(input,"s","size"); |
|
if(s.Exist()) |
|
{ |
|
bool suc=true; |
|
f.size=s(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
casevalid=true; |
|
} |
|
} |
|
|
|
// Family |
|
{ |
|
BaseM2String family(input,"family","f"); |
|
if(family.Exist()) |
|
{ |
|
bool suc=true; |
|
f.family=family(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
casevalid=true; |
|
} |
|
} |
|
|
|
// Color |
|
{ |
|
BaseMT2Color color(input,"color","c"); |
|
if(color.Exist()) |
|
{ |
|
bool suc=true; |
|
f.color=color(&suc); |
|
if(!suc) goto fail; // Parsing error |
|
casevalid=true; |
|
} |
|
} |
|
|
|
if(casevalid || upd) return f; // Pen created or updated |
|
} |
|
|
|
// Case 6 and 7 |
|
if(2==size || 3==size) |
|
{ |
|
Base2Width s(input,0); |
|
Base2String fam(input,1); |
|
Base2Color c(input,2); |
|
bool suc=true; |
|
f.size=s(&suc); |
|
f.family=fam(&suc); |
|
f.color=c(&suc); |
|
if(!suc) goto fail; // Something wrong |
|
return f; |
|
} |
|
|
|
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
|
|
|